我有下面的一段代码:
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 应该按照前面提到的顺序打印。任何人都可以解释这是什么行为?
我有下面的一段代码:
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 应该按照前面提到的顺序打印。任何人都可以解释这是什么行为?
printf()
%p
在传递浮点值时,需要格式说明符的指针。这是未定义的行为。
如果要打印地址,则传递地址:
printf("%f %p",i, &i);
如果你打开警告,你会看到问题:
警告:格式“%p”需要“void *”类型的参数,但参数 3 的类型为“double”[-Wformat]
你正在做的是未定义的行为。%p
格式说明符承诺您传递的是一个指针(特别是一个指针void*
),而您传递的是 a double
(当传递给可变参数函数时,float
值会被提升为)。因此,一旦您无法满足要求,编译器和实现就可以自由地做任何他们想做的事情,并且在第二种情况下打印出 0 而不是 85 是完全合法的。double
printf
可能发生的情况是编译器使用调用约定将浮点值放在单独的寄存器(例如 x87 浮点堆栈或 SSE2 SIMD 寄存器)而不是堆栈中,而像指针这样的整数值被传递堆栈。因此,当实现看到%p
格式说明符时,它会尝试从堆栈中读取参数,而实际上参数实际上在其他地方。
正如其他人所提到的,您确实应该使用该-Wall
选项进行编译(假设 GCC 或与 GCC 兼容的编译器)。它将帮助您捕获这些类型的错误。
您可能遇到了一些未定义的行为;将浮点数作为指针打印绝对没有意义。
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 级别,浮点和指针参数通过不同的寄存器传递。因此,实现可能会将所涉及的任何寄存器的(未初始化的或旧的)内容打印为指针。