2016-01-03 8 views
0

在6.5.2.2.6 $的C11标准:这条语句在C11标准(关于可变参数函数)中意味着什么?

如果表示所调用的函数的表达具有类型 不包括原型,整数提升上 执行的每个参数,并且该参数将类型浮点数提升为 双。这些被称为默认参数促销。如果参数个数不等于参数个数,则 行为未定义。 如果函数的定义类型为 包含原型,并且原型以省略号 (,...)结尾,或者升级后的参数类型不是 与参数类型兼容,行为是未定义的 。如果使用不包含原型 的类型定义函数,并且升级后 之后的参数类型与升级之后的参数类型不兼容,则 行为未定义,但以下情况除外:。 ..

这是什么意思 - 我真的无法理解它(特别是第一部分)。从我可以然而,这意味着定义一个函数是这样的:

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

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

回答

4

的情况如下:您可以将函数声明为不带参数列表,并调用这个函数:

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) 
{ 
    // ... 
} 

你现在引述说,该行为是不确定的,如果该参数的类型在这个定义是不符合提拔类型呼叫的兼容,还是standardese如果参数列表以省略号结尾。

作为一个必然结果,它遵循,如果你想使用带有可变参数的函数(使用<stdarg.h>设施访问的参数),则必须用原型声明函数:

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

现在c转换为int,因为第一个参数是键入的,第二个和第三个参数是默认提升的,因为它们是作为省略号的一部分传递的。 f的定义现在必须使用相同的声明。如果您愿意,以设备可访问的方式传递参数可能需要编译器提前了解,因此您必须在进行调用之前提供参数列表。

1

措辞有点混乱。整个段落正在讨论在调用函数时没有为函数声明原型的情况,因此您突出显示的部分是针对调用函数时没有声明原型的情况,而是在使用原型时该功能被定义。这里有一个例子:

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,行为是未定义的,因为elipses用在定义的原型中。

+1

这个C标准很奇怪。您向我展示的所有这些省略号涉及哪些部分?因为它们存在于我强调的标准声明中。 – AnArrayOfFunctions

+0

@FISOCPP您突出显示的句子提到了两种情况,其中一种涉及'...'参数。 Vaughn Cato的例子是指另一种情况。 – fuz

+1

@FISOCPP:你突出显示的部分是针对两种不同的情况。我已经将我的答案扩展到包括elipses案例。 –

相关问题