Function declarations
Объявление функции вводит идентификатор , который обозначает функцию и, опционально, определяет типы параметров функции ( прототип ). Объявления функций (в отличие от определений ) могут появляться как в области видимости блока, так и в области видимости файла.
Содержание |
Синтаксис
В грамматике объявлений при объявлении функции последовательность type-specifier , возможно модифицированная декларатором, обозначает возвращаемый тип (которым может быть любой тип, кроме массивов и типов функций), а declarator имеет одну из трёх (до C23) двух (начиная с C23) форм:
noptr-declarator
(
parameter-list
)
attr-spec-seq
(необязательно)
|
(1) | ||||||||
noptr-declarator
(
identifier-list
)
attr-spec-seq
(необязательно)
|
(2) | (до C23) | |||||||
noptr-declarator
(
)
attr-spec-seq
(необязательно)
|
(3) | ||||||||
где
| noptr-declarator | - | любой декларатор за исключением неподписанного указательного декларатора. Идентификатор, содержащийся в этом деклараторе, становится идентификатором функции. |
| parameter-list | - | либо одиночное ключевое слово void либо список параметров через запятую, который может заканчиваться параметром с многоточием |
| identifier-list | - | список идентификаторов через запятую, возможен только если этот декларатор используется как часть определения функции в старом стиле |
| attr-spec-seq | - | (C23) опциональный список атрибутов , применяемых к типу функции |
int max(int a, int b); // declaration int n = max(12.01, 3.14); // OK, conversion from double to int
int max(a, b) int a, b; // definition expects ints; the second call is undefined { return a > b ? a : b; } int n = max(true, (char)'a'); // calls max with two int args (after promotions) int n = max(12.01f, 3.14); // calls max with two double args (after promotions)
Объяснение
Тип возвращаемого значения функции, определяемый спецификатором типа в спецификаторах-и-квалификаторах и возможно модифицируемый декларатором как обычно в объявлениях , должен быть типом не-массива объекта или типом void . Если объявление функции не является определением, возвращаемый тип может быть неполным . Возвращаемый тип не может быть cvr-квалифицирован: любой квалифицированный возвращаемый тип корректируется до своей неквалифицированной версии для построения типа функции.
void f(char *s); // возвращаемый тип - void int sum(int a, int b); // возвращаемый тип sum - int int (*foo(const void *p))[3]; // возвращаемый тип - указатель на массив из 3 int double const bar(void); // объявляет функцию типа double(void) double (*barp)(void) = bar; // OK: barp - указатель на double(void) double const (*barpc)(void) = barp; // OK: barpc также указатель на double(void)
Деклараторы функций могут комбинироваться с другими деклараторами при условии, что они могут совместно использовать свои спецификаторы типа и квалификаторы
int f(void), *fip(), (*pfi)(), *ap[3]; // объявляет две функции и два объекта inline int g(int), n; // Ошибка: квалификатор inline предназначен только для функций typedef int array_t[3]; array_t a, h(); // Ошибка: тип массива не может быть возвращаемым типом для функции
Если объявление функции появляется вне любой функции, идентификатор, который она вводит, имеет область видимости файла и внешнюю линковку , если только не используется static или не видно более раннее статическое объявление. Если объявление происходит внутри другой функции, идентификатор имеет область видимости блока (а также либо внутреннюю, либо внешнюю линковку).
int main(void) { int f(int); // внешняя компоновка, область видимости блока f(1); // определение должно быть доступно где-то в программе }
Параметры в объявлении которое не является частью определения функции (до C23) не обязательно должны иметь имена:
int f(int, int); // объявление // int f(int, int) { return 7; } // Ошибка: параметры должны быть именованными в определениях // Это определение разрешено начиная с C23
Каждый параметр в parameter-list представляет собой объявление , которое вводит одну переменную, со следующими дополнительными свойствами:
- идентификатор в деклараторе является необязательным (за исключением случаев, когда это объявление функции является частью определения функции) (до C23)
int f(int, double); // OK int g(int a, double b); // также OK // int f(int, double) { return 1; } // Ошибка: определение должно именовать параметры // Это определение разрешено начиная с C23
- единственным спецификатором класса хранения , допустимым для параметров, является register , и он игнорируется в объявлениях функций, не являющихся определениями
int f(static int x); // Ошибка int f(int [static 10]); // OK (static в индексе массива не является спецификатором класса памяти)
- любой параметр типа массива преобразуется в соответствующий тип указателя , который может быть квалифицирован, если между квадратными скобками объявителя массива присутствуют квалификаторы (начиная с C99)
int f(int[]); // объявляет int f(int*) int g(const int[10]); // объявляет int g(const int*) int h(int[const volatile]); // объявляет int h(int * const volatile) int x(int[*]); // объявляет int x(int*)
- любой параметр типа функции корректируется до соответствующего типа указателя
int f(char g(double)); // объявляет int f(char (*g)(double)) int h(int(void)); // объявляет int h(int (*)(void))
-
список параметров может завершаться
, ...или быть...(начиная с C23) , подробности смотрите в разделе variadic functions .
int f(int, ...);
- параметры не могут иметь тип void (но могут иметь тип указателя на void). Специальный список параметров, состоящий исключительно из ключевого слова void используется для объявления функций, которые не принимают параметров.
int f(void); // OK int g(void x); // Ошибка
- любой идентификатор, появляющийся в списке параметров, который может быть интерпретирован как имя typedef или как имя параметра, трактуется как имя typedef: int f ( size_t , uintptr_t ) разбирается как новый стиль объявления функции с двумя безымянными параметрами типа size_t и uintptr_t , а не как старый стиль объявления, начинающий определение функции с двумя параметрами с именами " size_t " и " uintptr_t ".
- параметры могут иметь неполный тип и могут использовать нотацию VLA [ * ] (since C99) (за исключением того, что в определении функции типы параметров после преобразования массива в указатель и функции в указатель должны быть полными).
|
Последовательности спецификаторов атрибутов также могут применяться к параметрам функций. |
(начиная с C23) |
См. function call operator для дополнительной информации о механике вызова функции и return для возврата из функций.
Примечания
|
В отличие от C++, деклараторы f ( ) и f ( void ) имеют разное значение: декларатор f ( void ) является декларатором нового стиля (прототипом), который объявляет функцию без параметров. Декларатор f ( ) является декларатором, который объявляет функцию с неопределённым количеством параметров (если не используется в определении функции) int f(void); // declaration: takes no parameters int g(); // declaration: takes unknown parameters int main(void) { f(1); // compile-time error g(2); // undefined behavior } int f(void) { return 1; } // actual definition int g(a,b,c,d) int a,b,c,d; { return 2; } // actual definition |
(до C23) |
В отличие от function definition , список параметров может быть унаследован из typedef
typedef int p(int q, int r); // p - это тип функции int(int, int) p f; // объявляет int f(int, int)
|
В C89, specifiers-and-qualifiers был необязательным, и если он опущен, возвращаемый тип функции по умолчанию становился int (возможно, изменённым declarator ). *f() { // function returning int* return NULL; } |
(до C99) |
Отчёты о дефектах
Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| DR 423 | C89 | the return type might be qualified | the return type is implicitly disqualified |
Ссылки
- Стандарт C23 (ISO/IEC 9899:2024):
-
- 6.7.7.4 Деклараторы функций (включая прототипы) (стр.: 130-132)
- Стандарт C17 (ISO/IEC 9899:2018):
-
- 6.7.6.3 Деклараторы функций (включая прототипы) (стр: 96-98)
- Стандарт C11 (ISO/IEC 9899:2011):
-
- 6.7.6.3 Деклараторы функций (включая прототипы) (стр: 133-136)
- Стандарт C99 (ISO/IEC 9899:1999):
-
- 6.7.5.3 Деклараторы функций (включая прототипы) (стр: 118-121)
- Стандарт C89/C90 (ISO/IEC 9899:1990):
-
- 3.5.4.3 Деклараторы функций (включая прототипы)
Смотрите также
|
C++ documentation
для
Объявление функции
|