Прототипы функций
Объявление функции предшествует ее определению и указывает имя, тип возвращаемого значения, класс хранения и другие атрибуты функции. Чтобы объявление функции стало ее прототипом, оно должно также задавать типы и идентификаторы аргументов функции.
Синтаксис
declaration:
спецификаторы-объявления последовательность-атрибутов необ список-инициализаторов-и-деклараторов необ**;**/* последовательность-атрибутов необ относится только к системам Microsoft */
спецификаторы-объявления:
спецификатор-класса-хранения спецификаторы-объявления необспецификатор-типа спецификаторы-объявления необ
квалификатор-типа спецификаторы-объявления необ
список-инициализаторов-и-деклараторов:
инициализатор-деклараторсписок-инициализаторов-и-деклараторов , инициализатор-декларатор
инициализатор-декларатор:
декларатордекларатор = инициализатор
declarator:
указатель необ прямой-деклараторпрямой-декларатор: /* Декларатор функции */
прямой-декларатор ( список-типов-параметров ) /* Декларатор нового стиля */прямой-декларатор ( список-идентификаторов необ ) /* Декларатор устаревшего стиля */
Прототип имеет ту же форму, что и определение функции, но завершается точкой с запятой сразу после закрывающей круглой скобки и поэтому не имеет тела. В любом случае возвращаемый тип должен соответствовать возвращаемому типу, указанному в определении функции.
Ниже перечислены важные случаи применения прототипов функций:
Они определяют тип возвращаемого значения для функции, возвращающих типы, отличные от int. Хотя для функций, возвращающих значения int, прототипы не обязательны, рекомендуется их использовать.
Без полных прототипов выполняются стандартные преобразования, но не производится попытка сравнения типа или количества аргументов с количеством параметров.
Прототипы используются для инициализации указателей на функции до определения этих функций.
Список параметров используется для проверки соответствия аргументов в вызове функции и параметров в ее определении.
Преобразованный тип каждого параметра определяет интерпретацию аргументов, помещаемых в стек при вызове функции. Несоответствие типов аргументов и параметров может приводить к неправильной интерпретации аргументов в стеке. Например, если на 16-разрядном компьютере в качестве аргумента передается 16-разрядный указатель, объявленный как long, первые 32 бита в стеке интерпретируются как параметр long. Эта ошибка создает проблемы не только с параметром long, но и со всеми последующими параметрами. Ошибки такого типа можно обнаруживать, объявляя полные прототипы для всех функций.
Прототип задает атрибуты функции, поэтому вызовы функции, предшествующие ее определению (или производимые из других файлов исходного кода), можно проверять на соответствие типов аргументов и возвращаемого типа. Например, если в прототипе указан описатель класса хранения static, необходимо также задать класс хранения static в определении функции.
Полные объявления параметров (int a) могут использоваться совместно с абстрактными деклараторами (int) в одном объявлении. Например, следующее объявление является допустимым:
int add( int a, int );
Прототип может содержать как тип, так и идентификатор для каждого выражения, которая передается в качестве аргумента. Однако область действия такие идентификатор распространяется только до конца объявления. Прототип также может отражать тот факт, что число аргументов является переменным, или что никакие аргументы не передаются. Без такого списка выявление несоответствий невозможно, поэтому компилятор не может создавать соответствующие диагностические сообщения. Дополнительные сведения о проверке типов содержатся в разделе Аргументы.
Теперь при компилировании с параметром компилятора /Za область действия прототипа в компиляторе Microsoft C соответствует стандарту ANSI. Это означает, что при объявлении тега struct или union в прототипе данный тег вставляется в этой области, а не в глобальной области. Например, если выполнять компиляцию с параметром /Za для обеспечения соответствия стандарту ANSI, то невозможно вызвать эту функцию без получение ошибки несоответствия типов:
void func1( struct S * );
Чтобы исправить код, определите или объявите struct или union в глобальной области перед прототипом функции:
struct S;
void func1( struct S * );
При использовании параметра /Ze данный тег по-прежнему находится в глобальной области.