Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Объявление функции предшествует ее определению и указывает имя, тип возвращаемого значения, класс хранения и другие атрибуты функции. Чтобы объявление функции стало ее прототипом, оно должно также задавать типы и идентификаторы аргументов функции.
Синтаксис
declaration
:
declaration-specifiers
attribute-seq
необ. init-declarator-list
необ. ;
/* attribute-seq
необ. относится только к продуктам Майкрософт */
declaration-specifiers
:
storage-class-specifier
declaration-specifiers
необ.
type-specifier
declaration-specifiers
необ.
type-qualifier
declaration-specifiers
необ.
init-declarator-list
:
init-declarator
init-declarator-list
,
init-declarator
init-declarator
:
declarator
declarator
=
initializer
declarator
:
pointer
необ. direct-declarator
direct-declarator
: /* Оператор объявления функции */
direct-declarator
(
parameter-type-list
)
/* Декларатор нового стиля */
direct-declarator
(
identifier-list
opt )
/* Устаревший декларатор */
Прототип имеет ту же форму, что и определение функции, за исключением того, что она завершается точкой с запятой сразу после закрывающей скобки и поэтому не имеет тела. В любом случае возвращаемый тип должен соответствовать возвращаемому типу, указанному в определении функции.
Ниже перечислены важные случаи применения прототипов функций:
Они определяют тип возвращаемого значения для функции, возвращающих типы, отличные от
int
. Хотя для функций, возвращающих значения типаint
, прототипы не обязательны, рекомендуется их использовать.Без полных прототипов выполняются стандартные преобразования, но не производится попытка сравнения типа или количества аргументов с количеством параметров.
Прототипы используются для инициализации указателей на функции до определения этих функций.
Список параметров используется для проверки соответствия аргументов в вызове функции и параметров в ее определении.
Преобразованный тип каждого параметра определяет интерпретацию аргументов, помещаемых в стек при вызове функции. Несоответствие типов аргументов и параметров может приводить к неправильной интерпретации аргументов в стеке. Например, если на 16-разрядном компьютере в качестве аргумента передается 16-разрядный указатель, объявленный как параметр long
, первые 32 бита в стеке интерпретируются как параметр типа long
. Эта ошибка создает проблемы не только с параметром long
, но и со всеми последующими параметрами. Ошибки такого типа можно обнаруживать, объявляя полные прототипы для всех функций.
Прототип устанавливает атрибуты функции. После этого вызовы функций, предшествующие определению функции (или в других исходных файлах), можно проверять на несоответствие типов аргументов и возвращаемых типов. Например, если в прототипе указан описатель класса хранения static
, необходимо также задать класс хранения static
в определении функции.
Полные объявления параметров (int a
) могут использоваться совместно с абстрактными операторами объявления (int
) в одном объявлении. Например, следующее объявление является допустимым:
int add( int a, int );
Прототип может содержать как тип, так и идентификатор для каждого выражения, которое передается в качестве аргумента. Однако область действия таких идентификаторов распространяется только до конца объявления. Прототип также может отражать тот факт, что число аргументов является переменным, или что никакие аргументы не передаются. Без такого списка выявление несоответствий невозможно, поэтому компилятор не может создавать соответствующие диагностические сообщения. Дополнительные сведения о проверке типов содержатся в статье Аргументы.
Теперь область прототипа в компиляторе Microsoft C соответствует стандарту ANSI при компиляции с параметром /Za
. Если вы объявите в прототипе тег struct
или union
, этот тег добавляется именно в этой области, а не в глобальной области. Например, если выполнять компиляцию с параметром /Za
в соответствии со стандартом ANSI, эту функцию невозможно будет вызвать без получения ошибки несоответствия типов:
void func1( struct S * );
Чтобы исправить код, определите или объявите struct
или union
в глобальной области перед прототипом функции:
struct S;
void func1( struct S * );
В разделе /Ze
тег по-прежнему вводится в глобальной области.