Поделиться через


Прототипы функций

Объявление функции предшествует ее определению и указывает имя, тип возвращаемого значения, класс хранения и другие атрибуты функции. Чтобы объявление функции стало ее прототипом, оно должно также задавать типы и идентификаторы аргументов функции.

Синтаксис

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-listopt ) /* Устаревший декларатор */

Прототип имеет ту же форму, что и определение функции, за исключением того, что она завершается точкой с запятой сразу после закрывающей скобки и поэтому не имеет тела. В любом случае возвращаемый тип должен соответствовать возвращаемому типу, указанному в определении функции.

Ниже перечислены важные случаи применения прототипов функций:

  • Они определяют тип возвращаемого значения для функции, возвращающих типы, отличные от 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тег по-прежнему вводится в глобальной области.

См. также

Функции