函数声明
函数声明引入一个 标识符,该标识符指定一个函数,并可以选择指定函数参数的类型(原型)。函数声明(与 定义 不同)可以出现在块作用域和文件作用域中。
内容 |
[编辑] 语法
在函数声明的 声明语法 中,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)
[编辑] 解释
函数的返回值类型由 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
或之前的静态声明可见。如果声明出现在另一个函数中,则标识符具有块作用域(并且也具有内部或外部链接)。
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 起) |
有关函数调用机制和其他详细信息,请参阅 函数调用运算符,有关从函数返回的信息,请参阅 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) |
与 函数定义 不同,参数列表可以从 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 | 返回值类型可能被限定 | 返回值类型被隐式地取消限定 |