Spec-Zone.ru › C

Объявления функций

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

Синтаксис

В грамматике объявления функции последовательность 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)необязательный список атрибутов, применяемых к типу функции
1) Объявление функции нового стиля (C89). Это объявление вводит само обозначение функции и также служит прототипом функции для будущих выражений вызова функции, выполняя преобразования выражений аргументов к объявленным типам параметров и проверки времени компиляции количества аргументов.
int max(int a, int b); // declaration
int n = max(12.01, 3.14); // OK, conversion from double to int
2) (до C23) Объявление функции старого стиля (K&R). Это объявление не вводит прототип, и любые будущие выражения вызова функции будут выполнять стандартные преобразования аргументов и вызовут неопределённое поведение, если количество аргументов не соответствует количеству параметров.
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)
3) Объявление не-прототипной функции. Это объявление не вводит прототип(до C23). Объявление функции нового стиля, эквивалентное parameter-list 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++, деклараторы 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)

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

*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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API