变量函数(va_arg)不能用于float,而printf有用吗?有什么区别?

时间:2014-05-23 18:27:21

标签: c++ c floating-point variadic-functions

我碰巧在两年的问题中遇到了类似的情况:

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宣传 floatdouble

但有什么区别?如果他们都将float提升为double,为什么printf会正确地写出值,而va_arg会给我们这样的鼻子?

4 个答案:

答案 0 :(得分:5)

不是printf将float参数提升为double,它是编译器。换句话说,当您的va_argprintf或任何其他具有可变数量参数的函数获得控件时,所有float都已提升为double s ;原始float无法检索。

printfva_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),就像你一样。