在C中的printf中的-NaN

时间:2011-03-12 14:06:11

标签: c printf nan

我目前在某些计算中遇到了Raytracer“引擎”的问题。

  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错误。

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

2 个答案:

答案 0 :(得分:3)

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

当您将eyexeyey和其他参数传递给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,其中xxxxxxxxx是info->vx的值。无论该值如何,这都是NaN的IEEE 754表示,或“不是数字”。它有符号位设置,因此一些实现可能会选择将其解释为“负NaN”,尽管它具有与常规NaN相同的语义。

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

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

答案 1 :(得分:1)

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

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