原型之痛
ANSI C函数原型的目的是使C语言称为一种更加可靠的语言。建立原型就是为了消除一种普通(但很难发现)的错误,即形参和实参之间类型不匹配。
ANSI C的函数原型就是采取一种新的函数声明形式,把参数的类型也包含在声明之中。函数的定义也做了相应的改变以匹配声明。这样,编译器就可以在函数的声明和使用之间进行检查。
K&R C的函数声明与ANSI C原型的对比
//声明 K&R C //原型 ANSI
int foo(); int foo(int a, int b);
或
int foo(int, int);
//定义 K&R C //定义 ANSI C
int foo(a, b) int foo(int a, int b) {
int a, b;{...} ...
}
可以在ANSI C中使用int foo(void);这样的形式来表示“没有参数”,尽管它看上去与传统的C不一样。
函数原型不仅改变了C语言的语法,而且引入了一种微妙的语义区别(不是人们所希望的),K&R C函数参数会进行类型提升。在被调用函数的函数体内,这些值会根据函数定义使参数的声明类型自动裁剪为该类型。之所以要这么做,原因是为了简化编译器---所有的东西都是同一长度。如果只固定使用几种类型,将大大简化参数的传递,尤其是在非常老式的K&R C编译器中(不能传递struct作为参数)。这种 编译器只允许3中类型作为参数:int、double和指针。所有的参数都统一为标准长度,被调用函数会根据需要对它们进行裁剪。
相反,如果使用了函数原型,缺省参数提升就不会发生。编译器就会假定参数是准确声明的,于是便不进行类型提升,并据此产生代码。