【问题标题】:Variadic function (va_arg) doesn't work with float, while printf does? What the difference is?可变参数函数 (va_arg) 不适用于 float,而 printf 可以?有什么区别?
【发布时间】:2014-05-23 18:27:20
【问题描述】:

两年前我刚好遇到类似这个问题的情况:

Variadic function (va_arg) doesn't work with float?

据说问题是促进当我们调用类似的东西时float to double

    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's 到double's。

但是有什么区别呢?如果两者都将float提升为double,那为什么printf会正确写入值,而va_arg却给了我们这样的鼻恶魔?

【问题讨论】:

  • 是什么让你认为printf 试图解析参数,它知道会被提升为double,就像floatprintf 函数总是知道在 float 将被传递的地方期待 double。你的功能没有。这就是区别。
  • 感谢大家的精彩回答!现在我明白了,不仅是它是如何工作的,而且还有更多。

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


【解决方案1】:

不是printf 将float 参数提升为double,而是编译器 做到了。换句话说,当您的va_argprintf 或任何其他具有可变数量参数的函数获得控制权时,所有floats 已经被提升为doubles;无法检索原始的 floats。

printfva_arg的区别在于printf遵循标准制定的规则,当在格式字符串。因此,它成功地获得了一个double,其中包含float 的提升值,并产生了所需的输出。

另一方面,当va_arg 调用val = va_arg(vl, float) 时,它会忽略提升规则,并得到一个无效的表示作为回报。

【讨论】:

  • 注意:如果printf() 的参数为charshort 或小于int 的任何值,则同样的问题适用:需要将intva_arg() 一起使用。跨度>
  • 非常感谢您的回答,现在我很清楚这里吵闹的原因是什么。
【解决方案2】:

printf 不接受 float 类型的参数。

例如,"%f" 格式说明符需要 double 类型的参数。 "%Lf" 需要 long double 类型的参数。没有格式需要 float 类型的参数(无论如何,它都会被提升为 double,而不是由 printf 本身,而仅仅是因为调用可变参数函数的语义)。

因此假设printf 是用C 实现的,并且它使用&lt;stdarg.h&gt; 机制来读取它的参数,那么在printf 的实现中没有为float 类型调用va_arg()

任何尝试为float 类型调用va_arg() 的可变参数函数都会有未定义的行为,因为这样的函数不能有float 参数。 printf 有效,因为它不这样做。

【讨论】:

    【解决方案3】:

    可变参数函数的参数获得特殊的提升规则。

    与此相关的是,将浮点数作为变量参数传递会提升为双精度数。这意味着您不能将参数提取为浮点数,因为它已作为双精度传递。这是由编译器完成的,与printf无关。

    这意味着代码val = va_arg(vl, float) 无效,因为参数不是浮点数,而是双精度数。 如果您确实需要将传入的值作为浮点数处理,那么您最多可以这样做

    float val = (float) va_arg(vl, double)
    

    请注意, printf 的 %f 说明符需要 double 类型的参数,而不是 float

    【讨论】:

      【解决方案4】:

      但是有什么区别呢?如果两者都将float提升为double,为什么printf写值正确,而va_arg给了我们这样的鼻恶魔?

      除了printf 的编码方式将float 视为double 之外,没有任何区别。换句话说,在printf 内部的某个地方,当格式字符串包含应该有一个浮点数的信息时,函数会执行va_arg(vl, double),就像您所做的那样。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-04
        • 2011-10-27
        相关资源
        最近更新 更多