C 参考手册
- C 语言
- C 的历史
- 基本概念
- 表达式
- 声明
- 初始化
- 函数
- 语句
- 静态断言
- 字符常量
- 函数声明
- 函数定义
- 转义序列
- 翻译阶段
- 标识符
- 作用域
- 生存期
- 查找与命名空间
- ASCII 码表
- 类型
- 遵从性
- 算术类型
- restrict 类型限定符
- 类型
- 对象与对齐
- 主函数
- 未定义行为
- 内存模型
- if 语句
- switch 语句
- for 循环
- while 循环
- do-while 循环
- continue语句
- break 语句
- goto语句
- return 语句
- 值类别
- 求值顺序
- 整数常量
- 浮点常量
- 字符串字面量
- 复合字面量
- 常量表达式
- 隐式转换
- 成员访问运算符
- 逻辑运算符
- 比较运算符
- 算术运算符
- 赋值运算符
- 自增/自减运算符
- 其他运算符
- sizeof 运算符
- _Alignof 运算符
- 转型运算符
- C 运算符优先级
- 泛型选择
- 标量初始化
- 数组初始化
- 结构体与联合体初始化
- 指针声明
- 数组声明
- 枚举
- 存储类指定符
- const 类型限定符
- volatile 类型限定符
- 结构体声明
- 联合体声明
- 位域
- _Alignas
- typedef 声明
- 原子类型
- 外部及试探性定义
- inline 函数指定符
- _Noreturn 函数指定符
- 变长参数
- 内联汇编
- 可分析性
- 替用运算符及记号
- C 关键词
- 预处理器
- C 标准库头文件
- 类型支持
- 程序支持工具
- 变参数函数
- 错误处理
- 动态内存管理
- 日期和时间工具
- 字符串库
- 算法
- 数值
- 文件输入/输出
- 本地化支持
- 原子操作库
- 线程支持库
- 实验性 C 标准库
- 有用的资源
- 符号索引
- 注释
函数声明
函数声明引入指代函数的标识符,并可选地指定该函数的参数类型(原型)。函数声明(不同于定义)可以出现于块作用域和文件作用域中。
语法
在函数声明的声明文法中, type-specifier (类型说明符)序列,可选择地由声明器修饰,指代返回类型(可以是任何异于函数和数组的类型),而声明器有二种形式:
非指针声明符 ( 形参列表 )
|
(1) | ||||||||
非指针声明符 ( 标识符列表(可选) )
|
(2) | (C2x 前) | |||||||
非指针声明符 ( )
|
(3) | (C2x 起) | |||||||
其中
非指针声明符 | - | 任何无括号指针声明器以外的声明器。包含于此声明器中的标识符是成为函数指代器的标识符。 |
形参列表 | - | 为单一关键词 void 或参数的逗号分隔列表,可以以省略号参数结尾。 |
标识符列表 | - | 标识符的逗号分隔列表(仅当此声明器被用作旧式函数定义的一部分),必须在非定义的旧式声明中省略。 |
1) 新式 (C89) 函数声明。此声明不仅引入函数指代器自身,而且还为任何将来的函数调用表达式提供函数原型,强制将使用参数表达式转换成声明参数类型,还有编译时的参数数量检查。
int max(int a, int b); // 声明 int n = max(12.01, 3.14); // OK :从 double 转换到 int
2) (C2x 前) 旧式 (K&R) 函数声明。此声明不表现为函数原型,且任何将来的函数调用表达式都将进行默认参数提升,而且若实参数量不匹配形参数量则引起未定义行为。
int max(); int n = max(true, (char)'a'); // 以二个 int 参数调用 max (提升后) int n = max(12.01f, 3.14); // 以二个 double 参数调用 max (提升后) int max(a, b) int a, b; { return a>b?a:b; } // 定义期待 int ;第二个调用是未定义行为
3) (C2x 起) 拥有空参数列表的函数声明等价于以有由单个关键词 void 组成的 形参列表 的函数声明,即不接收参数的函数的声明。
解释
函数的返回类型,由 说明符与限定符 中的类型说明符确定,并且像在声明中一样可以由 声明符 修改,它必须是完整的非数组对象类型或类型 void 。
void f(char *s); // 返回类型为 void int sum(int a, int b); // sum 的返回类型为 int. int (*foo(const void *p))[3]; // 返回类型是指向 3 个 int 的数组的指针
函数的返回类型不能有 cvr 限定:为构造函数类型的目的,调整任何有限定返回类型为其无限定版本: double const foo(void) { return 0.; } // 声明 double(void) 类型函数 double (*foop)(void) = foo; // OK : foop 是指向 double(void) 的指针 double const (*foopc)(void) = foop; // OK : foopc 亦为指向 double(void) 的指针 |
(C17 起) |
函数声明器可以与其他声明器联合,只要他们共享其类型说明符和限定符。
int f(void), *fip(), (*pfi)(), *ap[3]; // 声明二个函数和二个对象 inline int g(int), n; // 错误: inline 说明符仅用于函数 typedef int array_t[3]; array_t a, h(); // 错误:数组类型不能作为函数返回类型
若函数声明器出现于任何函数外,则其引入的标识符拥有文件作用域和外部链接,除非使用 static
或较前的 static 声明可见。若声明出现于另一函数内,则标识符拥有块作用域(且亦拥有外部或内部链接)。
int main(void) { int f(int); // 外部链接,文件作用域 f(1); // 定义需要程序的某处可用 }
不是函数定义的一部分的声明中,参数不需要命名:
int f(int, int); // 声明 // int f(int, int) { return 7; } // 错误,参数在定义中必须命名
形参列表 中的每个参数是引入单个变量的声明,变量拥有下列额外属性:
- 声明器中的标识符是可选的(除非此函数声明是函数定义的一部分)
int f(int, double); // OK int g(int a, double b); // 也OK int f(int, double) { return 1; } // 错误:定义必须命名参数
- 仅有的得到允许的存储类说明符是
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))
- 参数列表可以以
, ...
终止,细节见变参数函数。
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 记法 [*] (C99 起)(除了在函数定义中,在数组到指针和函数到指针调整后,参数类型必须完整)
其他函数调用机制上的细节见函数调用运算符,关于从函数返回,见 return
。
注解
不同于 C++ ,声明器 f() 与 f(void) 拥有不同含义:声明器 f(void) 是新式(原型)声明器,声明函数不接收参数。声明器 f() 是旧式( K&R )声明器,声明函数接收未指定数量的参数(除非在函数定义中使用) int f(void); // 声明:不接收参数 int g(); // 声明:接收未知参数 int main(void) { f(1); // 编译时错误 g(2); // 未定义行为 } int f(void) { return 1; ) // 实际定义 int g(a,b,c,d) int a,b,c,d; { return 2; } // 实际定义 |
(C2x 前) |
和在函数定义中不同,参数列表可以从 typedef 继承
typedef int p(int q, int r); // p 是函数类型 int(int, int) p f; // 声明 int f(int, int)
C89 中, 说明符与限定符 是可选的,且若省略它,则函数的返回类型默认为 int (可以由 声明符 修改)。 *f() { // 返回 int* 的函数 return NULL; } |
(C99 前) |
引用
- C17 standard (ISO/IEC 9899:2018):
- 6.7.6.3 Function declarators (including prototypes) (p: 96-98)
- C11 standard (ISO/IEC 9899:2011):
- 6.7.6.3 Function declarators (including prototypes) (p: 133-136)
- C99 standard (ISO/IEC 9899:1999):
- 6.7.5.3 Function declarators (including prototypes) (p: 118-121)
- C89/C90 standard (ISO/IEC 9899:1990):
- 3.5.4.3 Function declarators (including prototypes)