我碰巧在两年的问题中遇到了类似的情况:
Variadic function (va_arg) doesn't work with float?
有人说,当我们称之为
之类的问题时促进浮动加倍 va_arg(arg, float)
我的问题是在这篇文章的最后,但首先让我们来看看@ Jack在上面链接的问题下面的答案:
#include <stdio.h>
#include <stdarg.h>
void foo(int n, ...)
{
va_list vl;
va_start(vl, n);
int c;
double val;
for(c = 0; c < n; c++) {
val = va_arg(vl, double);
printf("%f\n", val);
}
va_end(vl);
}
int main(void)
{
foo(2, 3.3f, 4.4f);
return 0;
}
输出:
3.300000
4.400000
现在,如果我们将val = va_arg(vl, double)
更改为val = va_arg(vl, float)
,我们就会得到(至少我参加MSVS 2012):
36893488147419103000.000000
2.162500
现在让我们回答我的问题。
在此主题中:C/C++ va_list not returning arguments properly
最多投票的答案,它的评论说printf
也宣传 float
到double
。
但有什么区别?如果他们都将float
提升为double
,为什么printf
会正确地写出值,而va_arg
会给我们这样的鼻子?
答案 0 :(得分:5)
不是printf
将float参数提升为double
,它是编译器。换句话说,当您的va_arg
或printf
或任何其他具有可变数量参数的函数获得控件时,所有float
都已提升为double
s ;原始float
无法检索。
printf
和va_arg
之间的区别在于printf
遵循标准设置的规则,并在请求提升类型的参数(即double
)时它在格式字符串中看到相应的格式说明符。因此,它成功获得double
,其中包含float
的提升值,并产生所需的输出。
另一方面,当va_arg
调用val = va_arg(vl, float)
时,它会忽略促销规则,并获得无效的回报。
答案 1 :(得分:3)
变量参数函数的参数获得特殊的促销规则。
这里的相关内容是将float作为变量参数传递给double。这意味着您不能将参数作为float提取,因为它已作为double传递。这是由编译器完成的,它与printf
无关。
这意味着代码val = va_arg(vl, float)
无效,因为参数不是浮点数,它是双精度数。
如果你真的需要将传入的值作为一个浮点数来处理,那么你最多可以做到
float val = (float) va_arg(vl, double)
请注意,printf的%f
说明符需要double
类型的参数,而不是float
答案 2 :(得分:3)
printf
不接受float
类型的参数。
例如,"%f"
格式说明符需要类型为double
的参数。 "%Lf"
需要long double
类型的参数。没有格式需要类型float
的参数(无论如何都会被提升为double
,而不是printf
本身,而仅仅是因为调用可变函数的语义。“ / p>
因此,假设printf
在C中实现,并且它使用<stdarg.h>
机制来读取其参数,则va_arg()
的类型float
没有被调用。实施printf
。
尝试为类型va_arg()
调用float
的任何可变函数都将具有未定义的行为,因为此类函数不能有float
个参数。 printf
有效,因为它没有这样做。
答案 3 :(得分:2)
但有什么区别?如果他们都将
float
提升为double
,为什么printf
会正确地写出值,而va_arg
会给我们这样的鼻子?
除了事实(在问题本身中说明)之外没有区别,printf
的编码方式是将float
视为double
。换句话说,在printf
内的某个地方,当格式字符串包含应该有浮点数的信息时,函数会va_arg(vl, double)
,就像你一样。