Spec-Zone.ru › C

Определения функций

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

C поддерживает два различных вида определений функций:

последовательность_атрибутов(необязательно) спецификаторы_и_квалификаторы декларатор_с_списком_параметров тело_функции (1)
спецификаторы_и_квалификаторы декларатор_с_списком_идентификаторов список_объявлений тело_функции (2) (до C23)

где

последовательность_атрибутов - (C23)необязательный список атрибутов, применяемых к функции
спецификаторы_и_квалификаторы - комбинация
  • спецификаторов типа, которые, возможно, модифицируются декларатором, образуя тип возвращаемого значения
  • спецификаторы класса хранения, которые определяют связь идентификатора (static, extern, или отсутствует)
  • спецификаторы функций inline, _Noreturn, или отсутствует
декларатор_с_списком_параметров - декларатор для типа функции, который использует список параметров для обозначения параметров функции
декларатор_с_списком_идентификаторов - декларатор для типа функции, который использует список идентификаторов для обозначения параметров функции
список_объявлений - последовательность объявлений, которые объявляют каждый идентификатор в декларатор_с_списком_идентификаторов. Эти объявления не могут использовать инициализаторы, и единственный разрешенный спецификатор класса хранения — register.
тело_функции - составной оператор, то есть заключенная в фигурные скобки последовательность объявлений и операторов, которая выполняется при вызове этой функции
1) Определение функции в новом стиле (C89). Это определение вводит саму функцию и служит прототипом функции для любых будущих выражений вызова функции, заставляя выполнение преобразований выражений аргументов в объявленные типы параметров.
int max(int a, int b)
{
    return a>b?a:b;
}
 
double g(void)
{
    return 0.1;
}
2) (до C23) Определение функции в старом стиле (K&R). Это определение не ведет себя как прототип, и любые будущие выражения вызова функции будут выполнять стандартные преобразования аргументов.
int max(a, b)
int a, b;
{
    return a>b?a:b;
}
double g()
{
    return 0.1;
}

Объяснение

Как и в случае с объявлениями функций, тип возвращаемого значения функции, определяемый спецификатором типа в спецификаторы_и_квалификаторы и, возможно, модифицированный декларатором, как обычно в объявлениях, должен быть полным типом объекта, не являющимся массивом, или типом void. Если тип возвращаемого значения должен быть квалифицирован cvr, он корректируется до своей неквалифицированной версии для целей построения типа функции.

void f(char *s) { puts(s); } // return type is void
int sum(int a, int b) { return a+b: } // return type is int
int (*foo(const void *p))[3] { // return type is pointer to array of 3 int
    return malloc(sizeof(int[3]));
}

Как и в случае с объявлениями функций, типы параметров корректируются от функций к указателям и от массивов к указателям для целей построения типа функции, а верхнеуровневые cvr-квалификаторы всех типов параметров игнорируются для определения совместимого типа функции.

В отличие от объявлений функций, безымянные формальные параметры не допускаются (в противном случае возникнут конфликты в определениях функций в старом стиле (K&R)), они должны быть именованными, даже если они не используются в теле функции. Единственным исключением является специальный список параметров (void).

(до C23)

Формальные параметры могут быть безымянными в определениях функций, поскольку определения функций в старом стиле (K&R) были удалены. Безымянные параметры недоступны по имени в теле функции.

(с C23)
int f(int, int); // declaration
// int f(int, int) { return 7; } // Error until C23, OK since C23
int f(int a, int b) { return 7; } // definition
int g(void) { return 8; } // OK: void doesn't declare a parameter

В теле функции каждый именованный параметр является выражением lvalue, у них есть автоматическая продолжительность хранения и объем блока. Размещение параметров в памяти (или если они вообще хранятся в памяти) не определено: это часть конвенции вызова.

int main(int ac, char **av)
{
    ac = 2; // parameters are lvalues
    av = (char *[]){"abc", "def", NULL};
    f(ac, av);
}

См. оператор вызова функции для получения дополнительной информации о механике вызова функции и return для возвращения из функций.

__func__

В каждом теле_функции доступна специальная предопределенная переменная __func__ с областью действия блока и статической продолжительностью хранения, как если бы она была определена сразу после открывающей фигурной скобки:

static const char __func__[] = "function name";

Этот специальный идентификатор иногда используется в сочетании с предопределенными константами макросов __FILE__ и __LINE__, например, с помощью assert.

(с C99)

Примечания

Список аргументов должен быть явно присутствовать в деклараторе, он не может быть унаследован от typedef

typedef int p(int q, int r); // p is a function type int(int, int)
p f { return q + r; } // Error

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

Кроме того, в определениях старого стиля не требовалось объявление для каждого параметра в список_объявлений. Любой параметр, объявление которого отсутствовало, имел тип int

max(a, b) // a and b have type int, return type is int
{
    return a>b?a:b;
}
(до C99)

Отчеты о дефектах

Следующие отчеты о дефектах, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C.

DR Применен к Поведение при публикации Правильное поведение
DR 423 C89 тип возвращаемого значения может быть квалифицирован тип возвращаемого значения неявно не квалифицируется

Ссылки

  • Стандарт C17 (ISO/IEC 9899:2018):
    • 6.9.1 Определения функций (стр.: 113-115)
  • Стандарт C11 (ISO/IEC 9899:2011):
    • 6.9.1 Определения функций (стр.: 156-158)
  • Стандарт C99 (ISO/IEC 9899:1999):
    • 6.9.1 Определения функций (стр.: 141-143)
  • Стандарт C89/C90 (ISO/IEC 9899:1990):
    • 3.7.1 Определения функций

См. также

Документация C++ по Определению функции

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/function_definition

Spec-Zone.ru

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