这个声明在 C11 标准中意味着什么(关于可变参数函数)?

What does this statement means in C11 standard (about variadic functions)?

C11 标准 6.5.2.2.6 美元:

If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions. If the number of arguments does not equal the number of parameters, the behavior is undefined. If the function is defined with a type that includes a prototype, and either the prototype ends with an ellipsis (, ...) or the types of the arguments after promotion are not compatible with the types of the parameters, the behavior is undefined. If the function is defined with a type that does not include a prototype, and the types of the arguments after promotion are not compatible with those of the parameters after promotion, the behavior is undefined, except for the following cases: ...

这是什么意思-我真的看不懂(尤其是第一部分)。然而,据我所知,这意味着定义这样的函数:

void func(int a, int b, ...)
{
}

然后调用它是未定义的行为,我认为这很愚蠢。

措辞有点混乱。整段都在讲函数调用时没有声明原型的情况,所以你高亮的那一段是针对函数调用时没有声明原型,但是调用时使用了原型的情况函数已定义。这是一个例子:

int main(int argc,char** argv)
{
    f(3.0f); /* undefined behavior */
    g(3.0);  /* undefined behavior */
}

int f(float v)
{
    return v;
}

int g(double v,...)
{
    return v;
}

在这个例子中,当调用f时,没有声明原型,所以3.0f被提升为double。但是,该函数稍后使用原型定义,该原型采用 float 而不是 double,因此行为未定义。

g 一样,行为未定义,因为定义的原型中使用了省略号。

情况如下:可以声明一个没有参数列表的函数,然后调用这个函数:

int main(void)
{ 
    extern void f();   // no parameter list!
    char c = 'x';
    f(c, 1UL, 3.5f);
}

在这种情况下,参数是 default-promoted:第一个参数被提升为 intunsigned int(取决于平台),第二个仍然是 unsigned long,第三个提升为double.

程序链接时,一些翻译单元需要包含函数的定义。定义总是包含一个参数列表,即使它是空的(但定义中的空参数列表意味着该函数不带参数,不像上面的 declaration-that-is-not-a-definition,它只是意味着没有提供有关参数):

void f(int, unsigned long, double)
{
    // ...
}

您现在引用的标准说,如果此定义中的参数类型与调用的提升类型不兼容,或者如果参数列表以省略号结尾,则行为未定义。

作为推论,如果你想使用带有可变参数的函数(使用 <stdarg.h> 的工具来访问参数),你必须用原型声明函数:

extern void f(int, ...);   // prototype (containing ellipsis)
f(c, 1UL, 3.5f);

现在c转换为int,因为第一个参数是有类型的,第二个和第三个参数和以前一样是default-promoted,因为它们是作为省略号的一部分传递的. f 的定义现在必须使用相同的声明。如果愿意,以 <stdarg.h> 工具可以访问的方式传递参数可能需要编译器的高级知识,因此您必须在调用之前提供参数列表。