在我的main
函数中,我使用以下代码
float f = 32.0;
func("test string %f", f);
func
(这些都是示例名称)声明如下
void func(const char *str, ...);
在我的函数实现中,我使用一个名为all_types
的联合来获取传递的参数的值
union all_types
{
void *v;
CLObject *obj;
char *s;
long l;
char c;
float f;
int i;
double d;
};
然后像这个
给这个联盟一个值union all_types *o = calloc(1, sizeof(union all_types));
while ((o->v = va_arg(list, void *)) != NULL)
现在,当我知道参数是一个浮点数时,它的值将非常奇怪(我设置了一个断点来计算它)。联合上的i
和l
值将是32,正如它们应该的那样。但是,f
值是一些奇怪的数字,如0.00000000000000000000000000000000000000000013592595
。有谁知道我为什么会这样做?此功能适用于我测试过的每种其他类型的对象。
答案 0 :(得分:3)
va_arg
宏的第二个参数是实际参数的实际类型。 va_arg
调用不会发生转换。如果您不知道实际参数的实际类型,那么您运气不好,因为无法找到答案。
请注意,默认参数转换确实发生在调用本身中,因此无法接收float
,char
或unsigned short
。 (float
将转换为double
,其他两个转换为int
或unsigned int
,具体取决于。)
这就是printf
格式使您指定参数类型的原因,float
除外。
答案 1 :(得分:3)
您正在执行的操作调用undefined behavior,variadic functions会将浮动转换为 double ,因为 void *而导致未定义的行为与 double 不兼容,因此您无法预期结果。我们可以通过转到draft C99 standard部分7.15.1.1
va_arg宏来看到这一点:
[...]如果没有实际的下一个参数,或者type与实际的下一个参数的类型不兼容(根据默认参数提升而提升),则行为未定义,[... ]
执行此操作的正确方法是:
o->d = va_arg(list, double)
你有格式说明符所以这应该是可能的:
"test string %f"
^^