4

我有下面的一段代码:

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 应该按照前面提到的顺序打印。任何人都可以解释这是什么行为?

4

3 回答 3

8

printf()%p在传递浮点时,需要格式说明符的指针。这是未定义的行为。

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

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

如果你打开警告,你会看到问题:

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

于 2013-06-25T04:55:50.757 回答
8

你正在做的是未定义的行为%p格式说明符承诺您传递的是一个指针(特别是一个指针void*),而您传递的是 a double(当传递给可变参数函数时,float值会被提升为)。因此,一旦您无法满足要求,编译器和实现就可以自由地做任何他们想做的事情,并且在第二种情况下打印出 0 而不是 85 是完全合法的。doubleprintf

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

正如其他人所提到的,您确实应该使用该-Wall选项进行编译(假设 GCC 或与 GCC 兼容的编译器)。它将帮助您捕获这些类型的错误。

于 2013-06-25T04:55:59.950 回答
3

您可能遇到了一些未定义的行为;将浮点数作为指针打印绝对没有意义。

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 级别,浮点和指针参数通过不同的寄存器传递。因此,实现可能会将所涉及的任何寄存器的(未初始化的或旧的)内容打印为指针。

于 2013-06-25T04:57:55.537 回答