va_arg是否使用前置或后置类型作为其第二个参数?

时间:2013-11-09 13:18:39

标签: c++ c variadic-functions

使用C级变量参数时:

void  example( size_t length, ... )
{
    va_list  list;
    T        x;
    va_start( list, length );
    //...
    x = va_arg( list, T );
    //...
    va_end( list );
}

某些类型在通过“...”时会被更改。例如,float变为double。如果T是这样的类型,我应该将原始类型或受损的类型放入va_arg吗?

如果C和C ++和/或标准修订版的答案不同,请注明。

(这里的快速浏览表明应该使用受损的类型。我希望不会,因为它已经被破坏,因为它需要用户计算类型,如果原始类型在类型别名后面,这是一种痛苦,尤其是没有通用原创的别名,例如size_t。希望我的帖子的标题更易于搜索。)

(更多的想法,我意识到目标变量必须用损坏的类型声明。所以使用va_arg中的受损类型,如果是真的,就比我想象的要愚蠢。我被C宠坏了有时候是++ 11的auto。)

1 个答案:

答案 0 :(得分:4)

  

如果T是这样的类型,我应该将原始类型或受损的类型放入va_arg吗?

如果T是受推广的类型,那么您应该输入转换后的类型,否则程序会有未定义的行为。

  

如果C和C ++和/或标准修订版的答案不同,请注明。

据我所知,C和C ++都需要这个。


  

经过深思熟虑,我意识到目标变量必须使用损坏类型

进行声明

不,这不是必须的。由于保证va_arg()宏的“调用”将是您指定为其第二个参数的类型,因此类似

float f = va_arg(args, double);

完全没问题,因为va_arg(...)会计算出double类型的表达式,然后会隐式转换为float


编辑:一些标准报价。

予。 C99,7.15.1.1.2:

  

[...]如果没有实际的下一个参数,或者type与实际的下一个参数的类型不兼容(根据默认参数提升而提升),则行为未定义[...]

II。 C ++ 11工作草案,18.10.3:

  

ISO C对标题va_start()<stdarg.h>宏的第二个参数的限制在本国际标准中有所不同。参数parmN是函数定义的变量参数列表中最右边的参数的标识符(恰好在......之前)。如果使用函数,数组或引用类型声明参数parmN,或者使用与传递没有参数的参数时产生的类型不兼容的类型,则行为未定义。 / p>

对我来说,上面的(C ++)引用似乎与默认促销的行为无关;但是,我认为通过说“限制是不同的”,它们意味着它们是相同的,除了以下[上面]条款。