C11标准为6.5.2.2.6美元:
如果表示被调用函数的表达式具有不包含原型的类型,则对每个参数执行整数提升,并将具有float类型的参数提升为double.这些被称为默认参数促销.如果参数数量不等于参数数量,则行为未定义.如果使用包含原型的类型定义函数,并且原型以省略号(,...)结尾,或者促销后的参数类型与参数类型不兼容,则行为未定义.如果使用不包含原型的类型定义函数,并且促销后的参数类型与促销后的参数类型不兼容,则行为未定义,但以下情况除外:...
这意味着什么 - 我真的无法理解它(特别是第一部分).从我可以,但它意味着定义这样的函数:
void func(int a, int b, ...) { }
然后调用它是未定义的行为,我认为这是愚蠢的.
情况如下:您可以声明一个没有参数列表的函数并调用此函数:
int main(void) { extern void f(); // no parameter list! char c = 'x'; f(c, 1UL, 3.5f); }
在这种情况下,参数是默认提升的:第一个参数被提升为int
或者unsigned int
(取决于平台),第二个参数保留unsigned long
,第三个参数被提升为double
.
程序链接时,某些翻译单元需要包含该功能的定义.定义总是包含一个参数列表,即使它是空的(但定义中的空参数列表意味着该函数不带参数,不像上面的声明那不是定义,它只是意味着没有提供有关参数的信息):
void f(int, unsigned long, double) { // ... }
您引用的标准现在表示如果此定义中的参数类型与提升的调用类型不兼容,或者参数列表以省略号结尾,则行为未定义.
作为推论,如果你想使用带有变量参数的函数(使用
访问参数的工具),你必须使用原型声明函数:
extern void f(int, ...); // prototype (containing ellipsis) f(c, 1UL, 3.5f);
现在c
转换为int
因为第一个参数是类型化的,第二个和第三个参数是默认提升的,因为它们是作为省略号的一部分传递的.的定义f
现在必须使用相同的声明.如果您愿意,以
设施可以访问的方式传递参数可能需要来自编译器的预先知识,因此您必须在进行调用之前提供参数列表.