在 C 标准化之前(也就是在 C89 之前),函数的定义不同。为了向后兼容,C11 仍然支持该样式。除非整个目的是为了获得乐趣,否则不要使用它:
int add_ints(); //forward-declaration has no parameters
add_ints(a, b)
//implicit type for return and parameters is int, this only works in pre-standard C or C89/C90
//int a, b; //remove this comment in C99/C11 for it to compile (also add return type int)
{
return a + b; //side note: old K&R compilers required parantheses around the return expression
}
在某种程度上,这些函数的参数行为类似于可变参数。调用者不知道函数需要什么参数(与可变参数相同)。它能够向它传递任何参数和任意数量的参数。但是,如果调用语句中的参数数量与声明中的参数数量不匹配,这当然是未定义的行为。
当然,由此产生了一个问题。如果调用者想要传递一个short,它如何知道该函数是期待一个short(并直接传递它)还是一个int(并且需要转换它)?它不能,因此达成了共同点。已决定:
-
char 和 short 晋升为 int
-
float 晋升为 double
以这种方式定义的所有函数(K&R 风格)和可变参数都会发生这种情况。这样,K&R 函数将永远不会期望 short 参数,因此编译器将始终将 short 参数提升为 int。
当然,正如@aschepler 所说,您仍然可以像这样定义函数:
short add_shorts(a, b)
short a, b;
{
return a + b;
}
这意味着参数首先转换为int并传递给函数,然后函数才将它们转换为short并添加它们。
小心printf():
之类的函数
printf("%.f", 3); //passes an int: UB and also wrong answer (my compiler prints 0)
printf("%.f", 3.0); //correct
printf("%.f", (double)3); //correct
您实际上可能经常看到 K&R 函数,尤其是如果作者没有注意将 void 关键字添加到不带参数的函数中:
int f1() //K&R function
{
return 0;
}
int f2(void) //Standard function
{
return 0;
}
int main(void) //Don't forget void here as well :P
{
int a = f1(); //Returns 0
int b = f2(); //Returns 0
int c = f1(100); //UB - invalid number of parameters, in practice just returns 0 :)
int d = f2(100); //Compiler error - parameter number/types don't match
//A good compiler would give a warning for call #3, but mine doesn't :(
}
编辑:不知道为什么,但 cppreference 将定义为 f1() 的函数分类为它们自己的函数类型(无参数,没有 void),而不是 K&R 函数。我面前没有标准,但即使标准说同样的事情,它们的行为也应该相同,并且有我提到的历史。
Default argument promotions
Function declarations in C