我当时正在研究默认参数提升问题,一度陷入困境。在C 2011(ISO / IEC 9899:2011)中,相关部分似乎是:
§6.5.2.2函数调用
¶6如果表示被调用的表达式函数的类型不包含原型,即整数对每个参数执行提升,并且具有类型float被提升为double。这些称为默认争论促销。如果参数个数不等于参数数量,行为是不确定的。如果功能是定义的类型包括原型,或者原型以省略号(,...)或参数的类型结尾升级后与参数类型不兼容,行为是不确定的。如果函数的类型定义为不包含原型,以及之后的参数类型促销与之后的参数不兼容升级,行为是不确定的,以下情况除外:
—一种提升类型是有符号整数类型,另一种提升类型是对应的无符号整数类型,值是两种类型均可表示;
-这两种类型都是指向合格或不合格版本的指针字符类型或无效。
在该段的最后三行中,讨论了在定义原型时不包括原型的函数类型。
它说如果升级后的参数类型与升级后的参数类型不兼容,则行为未定义。
现在,我非常怀疑,如果函数声明和函数定义均未包含本段中提到的原型,那么在本段的后三行中讨论的是哪些参数。 “ 提升后的参数”的含义是什么,因为我只研究过论据提升。什么是“ 参数促销”?
您还可以举例说明最后提到的特殊情况。如果有人可以用一个正确的例子来解释这一点,那将是非常有意义的。
在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
}
在某种程度上,这些函数的参数行为类似于varargs。调用者不知道函数需要什么参数(与varargs相同)。它能够传递给它任何参数以及任何数量的参数。但是,如果call语句中的参数数量与声明中的参数数量不匹配,则当然是未定义的行为。
当然,由此会产生一个问题。如果调用者想传递short
,它将如何知道该函数是期望short
(并直接传递)还是int
(并需要转换)?它不能,所以达成了共识。已决定:
char
和short
被提升为int
] >>float
被提升为double
对于以这种方式定义的所有函数(K&R样式)和varargs参数,都会发生这种情况。这样,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函数。我面前没有标准,但是即使标准说的是同一件事,它们的行为也应相同,并且具有我提到的历史。