Объявления функций
Объявление функции вводит идентификатор, обозначающий функцию, и необязательно указывает типы параметров функции (прототип). Объявления функций (в отличие от определений) могут появляться как в области блока, так и в области файла.
Синтаксис
В грамматике объявления функции последовательность type-specifier, возможно, модифицированная декларатором, обозначает тип возвращаемого значения (который может быть любым типом, кроме массива или типа функции), а declarator имеет одну из трёх форм:
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(с C23).Объяснение
Тип возвращаемого значения функции, определяемый спецификатором типа в specifiers-and-qualifiers и, возможно, модифицированный declarator как обычно в объявлениях, должен быть типом объекта, не являющимся массивом, или типом void. Если объявление функции не является определением, тип возвращаемого значения может быть неполным. Тип возвращаемого значения не может быть квалифицирован cvr: любой квалифицированный тип возвращаемого значения корректируется до его неквалифицированной версии для построения типа функции.
void f(char *s); // return type is void int sum(int a, int b); // return type of sum is int. int (*foo(const void *p))[3]; // return type is pointer to array of 3 int double const bar(void); // declares function of type double(void) double (*barp)(void) = bar; // OK: barp is a pointer to double(void) double const (*barpc)(void) = barp; // OK: barpc is also a pointer to double(void)
Деклараторы функций могут быть объединены с другими деклараторами, если они могут совместно использовать свои спецификаторы и квалификаторы типов.
int f(void), *fip(), (*pfi)(), *ap[3]; // declares two functions and two objects inline int g(int), n; // Error: inline qualifier is for functions only typedef int array_t[3]; array_t a, h(); // Error: array type cannot be a return type for a function
Если объявление функции находится вне любой функции, идентификатор, который оно вводит, имеет области файла и внешнюю связь, если не используется static или не видно предыдущего объявления static. Если объявление происходит внутри другой функции, идентификатор имеет область блока (и также либо внутреннюю, либо внешнюю связь).
int main(void)
{
int f(int); // external linkage, block scope
f(1); // definition needs to be available somewhere in the program
}Параметры в объявлении не являющемся частью определения функции(до C23) не нуждаются в именах:
int f(int, int); // declaration
// int f(int, int) { return 7; } // Error: parameters must be named in definitions
// This definition is allowed since C23Каждый параметр в parameter-list является объявлением, вводящим одну переменную со следующими дополнительными свойствами:
- идентификатор в деклараторе является необязательным (кроме случая, если это объявление функции является частью определения функции)(до C23)
int f(int, double); // OK
int g(int a, double b); // also OK
// int f(int, double) { return 1; } // Error: definition must name parameters
// This definition is allowed since C23- единственный спецификатор класса хранения, разрешённый для параметров, это
register, и он игнорируется в объявлениях функций, которые не являются определениями
int f(static int x); // Error int f(int [static 10]); // OK (array index static is not a storage class specifier)
- любой параметр типа массива корректируется до соответствующего типа указателя, который может быть квалифицирован, если есть квалификаторы между квадратными скобками декларатора массива(с C99)
int f(int[]); // declares int f(int*) int g(const int[10]); // declares int g(const int*) int h(int[const volatile]); // declares int h(int * const volatile) int x(int[*]); // declares int x(int*)
- любой параметр типа функции корректируется до соответствующего типа указателя
int f(char g(double)); // declares int f(char (*g)(double)) int h(int(void)); // declares int h(int (*)(void))
- список параметров может завершаться
, ...или быть...(с C23), см. функции с переменным числом аргументов для получения подробностей.
int f(int, ...);
- параметры не могут иметь тип
void(но могут иметь тип указатель на void). Специальный список параметров, состоящий только из ключевого словаvoid, используется для объявления функций, не принимающих параметры.
int f(void); // OK int g(void x); // Error
- любой идентификатор, который появляется в списке параметров, который может рассматриваться как имя typedef или как имя параметра, рассматривается как имя typedef:
int f(size_t, uintptr_t)парсится как декларатор нового стиля для функции, принимающей два безымянных параметра типа size_t и uintptr_t, а не декларатор старого стиля, который начинает определение функции, принимающей два параметра с именами "size_t" и "uintptr_t" - параметры могут иметь неполный тип и могут использовать обозначение VLA [*](с C99) (за исключением того, что в определении функции типы параметров после корректировки массива-в-указатель и функции-в-указатель должны быть полными)
| Последовательности спецификаторов атрибутов также могут быть применены к параметрам функций. | (с C23) |
См. оператор вызова функции для получения дополнительной информации о механике вызова функции и возврат для возвращения из функций.
Примечания
| В отличие от C++, деклараторы 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) |
В отличие от определения функции, список параметров может быть унаследован от typedef.
typedef int p(int q, int r); // p is a function type int(int, int) p f; // declares int f(int, int)
| В C89, specifiers-and-qualifiers было необязательно, и если оно опущено, тип возвращаемого значения функции по умолчанию был *f() { // function returning int*
return NULL;
} | (до C99) |
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C.
| DR | Применён к | Поведение, как опубликовано | Правильное поведение |
|---|---|---|---|
| DR 423 | C89 | тип возвращаемого значения мог быть квалифицирован | тип возвращаемого значения неявно дисквалифицируется |
Ссылки
- Стандарт 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++ для Объявления функции |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/function_declaration