繁体   English   中英

该声明在C11标准中(关于可变参数功能)意味着什么?

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

C11标准价格为6.5.2.2.6美元:

如果表示被调用函数的表达式的类型不包括原型,则对每个参数执行整数提升,而将float类型的参数提升为双精度。 这些称为默认参数提升。 如果参数数量不等于参数数量,则行为是不确定的。 如果使用包含原型的类型定义函数,并且原型以省略号(,...)结尾,或者升级后的参数类型与参数类型不兼容,则行为是不确定的。 如果使用不包含原型的类型定义函数,并且升级后的参数类型与升级后的参数类型不兼容,则除以下情况外,行为是不确定的:...

这意味着什么-我真的听不懂(尤其是第一部分)。 但是从我的能力来看,这意味着定义这样的函数:

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

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

情况如下:您可以声明一个没有参数列表的函数并调用此函数:

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

在这种情况下,参数是默认提升的:第一个参数提升为intunsigned int (取决于平台),第二个参数保持unsigned long ,第三个参数提升为double

链接程序时,某些翻译单元需要包含函数的定义。 定义始终包含一个参数列表,即使它是空的(但是定义中的空参数列表意味着该函数不接受任何参数,这与上面的声明不是定义的声明不同,在声明中,它仅意味着没有提供有关参数的信息):

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

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

因此,如果要使用带有可变参数的函数(使用<stdarg.h>来访问参数),则必须使用原型声明该函数:

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

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

措辞有点混乱。 整个段落都在讨论在调用函数时尚未声明原型的情况,因此您强调的部分是在调用函数时未声明原型的情况,而在调用该函数时使用原型的情况该功能已定义。 这是一个例子:

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 ,行为也是不确定的,因为在定义的原型中使用了椭圆。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM