如果位置改变,printf for float的行为会有所不同

时间:2013-06-25 04:52:04

标签: c floating-point printf

我在下面的代码:

float i=85.00;
printf("%f %p",i,i);

打印o / p:

85.00000 (nil)

但是当我改变下面的顺序时:

    float i=85.00;
    printf("%p %f",i,i);

o / p是:

(nil) 0.00000

虽然我希望按照上面提到的顺序打印类似的o / p。 任何人都可以解释一下这种行为是什么?

3 个答案:

答案 0 :(得分:8)

printf()期望格式说明符%p的指针,而您传递浮点数的。这是未定义的行为。

如果要打印地址,请传递地址:

printf("%f %p",i, &i);

如果您打开警告,则会发现问题:

  

警告:格式'%p'需要'void *'类型的参数,但参数3   类型为'double'[-Wformat]

答案 1 :(得分:8)

您正在做的是未定义的行为%p格式说明符承诺您传入一个指针(特别是void*指针),而您传递的是double,而float值会被提升传递给double等可变函数时传递给printf。因此,只要您不满足要求,编译器和实现就可以随意执行任何操作,并且在第二种情况下打印出0而不是85是完全合法的。

可能发生的事情是编译器正在使用一个调用约定,它将浮点值放在单独的寄存器中(例如x87浮点堆栈或SSE2 SIMD寄存器)而不是堆栈,而整数值就像指针一样在堆栈上传递。因此,当实现看到%p格式说明符时,它会尝试从堆栈中读取参数,而实际上参数实际上是在其他地方。

正如其他人所提到的,你应该真正使用-Wall选项进行编译(假设是GCC或GCC兼容的编译器)。它可以帮助你发现这些错误。

答案 2 :(得分:3)

你可能会遇到一些undefined behavior;打印浮动作为指针绝对没有意义。

GCC 4.8调用gcc -Wall正确警告你:

dwakar.c:5:3: warning: format '%p' expects argument of type 'void *', 
              but argument 3 has type 'double' [-Wformat=]
   printf("%f %p",i,i);
   ^

因此,请使用gcc -Wall编译代码并更正代码,直到没有给出警告为止。

请注意,在ABI级别,浮点和指针参数通过不同的寄存器传递。因此,实现可能会打印为指针所涉及的任何寄存器的(未初始化的或旧的)内容。