变量函数(va_arg)不适用于float,而printf有效吗? 有什么区别?
我碰巧在两年的问题中遇到了类似的情况:
变量函数(va_arg)不适用于float?
有人说,当我们称之为的时候,问题是促使浮动加倍
va_arg(arg, float)
我的问题是在这篇文章的最后,但首先让我们来看看@ Jack在上面链接的问题下面的答案:
#include #include 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没有正确地返回参数最多的投票答案,而且它的评论说printf
也将 float
的提升为double
。
但有什么区别? 如果它们都将float
提升为double
,为什么printf
正确地写入值,而va_arg
会给我们这样一个鼻子恶魔?
它不是printf
,它将float参数提升为double
,它是编译器 。 换句话说,当你的va_arg
或printf
或任何其他具有可变参数数量的函数获得控件时,所有的float
都已被提升为double
s; 原始float
不可用于检索。
printf
和va_arg
之间的区别在于printf
遵循标准设置的规则,并在格式字符串中看到相应的格式说明符时请求提升类型的参数(即double
)。 因此,它成功地获得了一个double
的float
值,并产生了所需的输出。
另一方面,当va_arg
调用val = va_arg(vl, float)
它会忽略促销规则,并获得无效的表示forms。
printf
不接受float
类型的参数。
例如, "%f"
格式说明符需要double
类型的参数。 "%Lf"
需要long double
类型的参数。 没有格式需要float
类型的参数(无论如何都会提升为double
,而不是printf
本身,而只是因为调用可变函数的语义)。
因此假设printf
是用C实现的,并且它使用
机制来读取它的参数,在printf
的实现中没有为float
类型调用va_arg()
。
任何尝试为类型float
调用va_arg()
可变函数都将具有未定义的行为,因为此类函数不能有float
参数。 printf
有效,因为它没有那样做。
变量参数函数的参数获得特殊的促销规则。
这里相关的一个是将float作为变量参数传递给double。 这意味着您无法将参数提取为float,因为它已作为double传递。 这是由编译器完成的,它与printf
无关。
这意味着代码val = va_arg(vl, float)
无效,因为参数不是float,它是double。 如果你真的需要将传入的值作为浮点数来处理,那么你最多可以做到
float val = (float) va_arg(vl, double)
请注意,printf的%f
说明符期望参数类型为double
,而不是float
但有什么区别? 如果它们都将
float
提升为double
,为什么printf
正确地写入值,而va_arg
会给我们这样一个鼻子恶魔?
除了事实(在问题本身中说明)之外,没有区别, printf
的编码方式是将float
视为double
。 换句话说,在printf
某个地方,当格式字符串包含应该有浮点数的信息时,该函数执行va_arg(vl, double)
,就像你一样。