【问题标题】:-NaN in printf in C-C 中 printf 中的 -NaN
【发布时间】:2011-07-14 01:39:35
【问题描述】:

我目前在某些计算中遇到了光线追踪器“引擎”的问题。

  info->eyex = -1000.0;
  info->eyey = 0.0;
  printf("%f et %f et %f et %f et %f\n", info->eyex, info->vx, info->eyey, info->vy, info->vz);

例如,在那段代码中,值看起来不错,但 info->eyex 给了我一个 -nan 错误。

这很奇怪,因为我之前重置了值。

【问题讨论】:

  • 由于printf颠覆了类型系统,所以在问printf的问题时需要指定变量是什么类型。
  • @Unlimited:您应该发布info 类定义。
  • @Unlimited:也可能有帮助:%f 可以视为float;尝试将%lf 用于double。
  • @artyom.stv:在 printf 和其他 varargs 函数中,float 会自动提升为 double。这是scanf,%lf 很重要。
  • @artyom:标准未描述printf 转换说明符"%lf"。允许编译器定义它作为扩展的作用......因此使用该特定扩展的程序在可移植性方面受到严重限制。

标签: c printf nan


【解决方案1】:

我的精神感觉告诉我eyex 被声明为int,而不是应有的double。当您将 -1000.0 分配给它时,它会被截断为整数 -1000(您的编译器应该在此处给您一个警告),它使用二进制补码表示法以二进制表示为 0xFFFFFC18。同样,假设eye也是一个整数,它的值0用二进制表示为0x00000000。

当您将eyex、eyey 和其他参数传递给printf 时,它们会被压入堆栈,以便它们位于内存中且地址不断增加。所以在 call 指令调用子程序之前,堆栈帧看起来像这样:

<top of stack>
0xFFFFFC18   ; eyex
(4-8 bytes)  ; vx
0x00000000   ; eyey
(4-8 bytes)  ; vy
(4-8 bytes)  ; vz

当printf 看到%f 格式说明符时,表示“从堆栈中取出8 个字节,将它们解释为double 值,然后打印出double 值”。所以它看到值 0xFFFFFC18xxxxxxxx,其中 xxxxxxxx 是 info-&gt;vx 的值。不管该值如何,这是 NaN 的 IEEE 754 表示,或“不是数字”。它设置了符号位,因此某些实现可能选择将其解释为“负 NaN”,尽管这与常规 NaN 具有相同的语义。

您的编译器还应该在此处警告您,您将错误类型的参数传递给printf——它期待double,但您没有传递它。 GCC 使用 -Wall 启用这些警告,我强烈建议启用。

因此,解决方案是将eyex 声明为double 类型(如果其他变量还没有的话,也可能是double)。或者,如果您不控制 eyex 等的定义(例如,因为它们是第三方库结构的一部分),那么您应该做的是使用 @987654343 将它们打印出来@修饰符将它们打印为整数,而不是%f,您还应该为它们分配整数值,例如-1000和0,而不是浮点值,例如-1000.0和0.0。

【讨论】:

  • 我认为浮点数在传递给可变参数函数时会提升为双精度数。这篇文章中的所有其他内容都是黄金。
  • @MSN:是的,当传递给可变参数函数时,浮点数确实会提升为双精度数。我在哪里说过相反的话?
  • 您发布的堆栈布局意味着浮点数被推送为 4 个字节。 int 将是,但浮点数将被推送为 8 个字节。
  • @MSN:好的,我明白你的意思了。我们实际上也不知道vx、vy 或vz 的数据类型。
【解决方案2】:

只是为了确认这一点。不过,我不知道究竟是什么触发了这种行为。 printf 在编译时进行了优化,并分析了格式字符串。可能它(错误地)假设了你的变量。尽管 %f 应该适用于双精度数和浮点数,但似乎并不总是这样(至少对于我正在使用的 gcc 4.4.5)

尝试将值分配给另一个变量,然后将其传递给 printf。虽然丑陋,但这为我解决了问题。

【讨论】:

    猜你喜欢
    • 2015-11-26
    • 2017-03-21
    • 2019-04-06
    • 2021-09-16
    • 2015-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-19
    相关资源
    最近更新 更多