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