C

C 知识量:16 - 74 - 317

9.2 ANSI C函数原型><

标准之前函数声明的缺陷- 9.2.1 -

在ANSI C标准之前,声明函数的方案有缺陷,因为只需要声明函数的类型,不用声明任何参数。例如使用旧式函数声明imax()函数:

int imax();

以上声明未给出imax()函数的参数个数和类型,如果调用时使用的参数个数或类型不匹配,编译器根本不会察觉出来,导致程序运行错误。

ANSI的解决方案- 9.2.2 -

针对以上缺陷,ANSI C标准要求在函数声明时还要声明参数的有关信息,也就是使用函数原型来声明函数的返回类型、参数的数量和每个参数的类型。以下是两种正确的imax()函数声明形式:

int imax(int, int);
int imax(int a, int b);

第1种形式使用以逗号分隔的类型列表,第2种形式在类型后面添加了变量名。需要注意的是,变量名只是个假名,不必与函数定义的形式参数名一致(以上声明的参数名就与定义中的形参不一致)。

有了以上信息,编译器就可以检查函数调用是否与函数原型匹配。其中,如果参数个数不匹配,编译器会给出错误提示,停止编译;如果参数类型不匹配,编译器会把实际参数的类型转换成形式参数的类型,并给出警告。例如:将浮点类型的实参转换为整数类型传递给imax()函数。

错误与警告的区别是:错误导致无法编译,而警告仍然允许编译。一些编译器在进行类似的类型转换时不会通知用户,因为C标准对此未作要求。但是,许多编译器都允许用户选择警告级别来控制编译器在描述警告时的详细程度。

无参数和未指定参数- 9.2.3 -

假设有以下函数原型:

void print_name();

一个支持ANSI C的编译器会假定用户没有用函数原型来声明函数,将不会检查参数。为了表明函数确实没有参数,正确的做法是在圆括号中使用void关键字:

void print_name(void);

支持ANSI C的编译器会解释为print_name()函数不接受任何参数,在调用该函数时,编译器将检查以确保没有使用参数。

一些函数接受许多参数,例如printf()和scanf()函数,其第一个参数是字符串,但是其他的参数的类型和数量都不固定。对于这种情况,ANSI C允许使用部分原型。例如对于printf()可以使用以下原型:

int printf(const char *, ...);

以上原型表明,第1个参数是一个字符串,可能还有其他未指定的参数。C库通过stdarg.h头文件提供了一个定义这类函数的标准方法。

函数原型的优点- 9.2.4 -

函数原型是C语言的一个强有力的工具,它让编译器可以捕获在使用函数时可能出现的许多错误或疏漏。

但是,也不一定必须使用函数原型,有一种方法可以省略函数原型,同时保留函数原型的优点。之所以使用函数原型,是为了让编译器在第1次执行到该函数之前就知道如何使用它,因此,把该函数的整个定义放在第1次调用之前,也有相同的效果。不过,正如前面提过的原因,这种方法只适用于函数的定义代码相对较短的情况。