命名空间
变体
操作

函数声明

来自 cppreference.com
< 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 或之前的静态声明可见。如果声明出现在另一个函数中,则标识符具有块作用域(并且也具有内部或外部链接)。

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 返回值类型可能被限定 返回值类型被隐式地取消限定

[编辑] 参考资料

  • C17 标准(ISO/IEC 9899:2018)
  • 6.7.6.3 函数声明符(包括原型)(p: 96-98)
  • C11 标准(ISO/IEC 9899:2011)
  • 6.7.6.3 函数声明符(包括原型)(p: 133-136)
  • C99 标准(ISO/IEC 9899:1999)
  • 6.7.5.3 函数声明符(包括原型)(p: 118-121)
  • C89/C90 标准(ISO/IEC 9899:1990)
  • 3.5.4.3 函数声明符(包括原型)

[编辑] 另请参阅

C++ 文档 for 函数声明