6.9.2 函数定义
语法
形式化语法
bnf
function-definition:
attribute-specifier-sequenceopt declaration-specifiers declarator function-body
function-body:
compound-statement1
2
3
4
5
2
3
4
5
约束
- 函数定义中声明的标识符,也就是函数名,必须具有函数类型;该类型由函数定义中的声明符部分给出。
- 函数的返回类型必须是
void,或者是除数组类型之外的完全对象类型。 - 声明说明符中的存储类说明符如果存在,只能是
extern或static。 - 如果形参列表仅由一个
void类型的形参组成,那么该形参声明符不得包含标识符。 - 未指定大小的变长数组类型,不得作为函数定义中的形参声明的一部分使用。
语义
- 函数定义中的可选属性说明符序列归属于该函数。
- 函数定义中的声明符给出被定义函数的名称,以及全部形参的类型,必要时也给出它们的名称。
- 该声明符同时也为同一翻译单元中后续对该函数的调用提供函数原型。
- 每个形参的类型按
6.7.7.4的规则调整。 - 如果一个接收可变数量实参的函数,在定义时没有使用以省略号结束的形参类型列表,那么行为未定义。
- 形参类型列表、紧随其后的声明符属性说明符序列,以及函数体的复合语句,共同形成一个单一的块。
- 每个形参都具有自动存储期;若该形参有标识符,则该标识符是一个左值。形参存储布局未指定。
- 进入函数时,每个变长修改形参的大小表达式,以及形参声明中使用的
typeof运算符,都会被求值;每个实参表达式的值会像赋值给对应形参那样转换到相应类型。 - 数组表达式和函数指示符在调用之前就已经先转换成指针。
- 所有形参完成赋值之后,才执行函数体的复合语句。
- 除非另有规定,如果执行到函数体末尾的
},并且调用方使用了该函数调用的值,那么行为未定义。
注
在函数定义中,函数的返回类型和其原型不能直接从 typedef 名继承:
c
typedef int F(void); // 类型 F 表示“无形参、返回 int 的函数”
F f, g; // f 和 g 的类型都与 F 兼容
F f { /* ... */ } // 错:语法/约束错误
F g() { /* ... */ } // 错:声明 g 返回一个函数
int f(void) { /* ... */ } // 对:f 的类型与 F 兼容
int g() { /* ... */ } // 对:g 的类型与 F 兼容
F *e(void) { /* ... */ } // e 返回一个指向函数的指针
F *((e))(void) { /* ... */ } // 同上:括号不影响含义
int (*fp)(void); // fp 指向一个类型为 F 的函数
F *Fp; // Fp 指向一个类型为 F 的函数1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
示例
示例 1
c
extern int max(int a, int b)
{
return a > b ? a : b;
}1
2
3
4
2
3
4
其中:
extern是存储类说明符;int是类型说明符;max(int a, int b)是函数声明符;- 函数体是:
c
{ return a > b ? a : b; }1
示例 2
把一个函数作为实参传给另一个函数时,可以写成:
c
int f(void);
/* ... */
g(f);1
2
3
2
3
那么 g 可以定义为:
c
void g(int (*funcp)(void))
{
/* ... */
(*funcp)(); /* 或 funcp(); */
}1
2
3
4
5
2
3
4
5
也可以等价地写成:
c
void g(int func(void))
{
/* ... */
func(); /* 或 (*func)(); */
}1
2
3
4
5
2
3
4
5