printf("%f", 1.0); //prints 1.0
但是。
printf("%f", 1); // prints 0.0
转换是如何发生的?
@Eric Postpischil
的评论不同,第一个双精度参数(或浮点参数,如果与函数的...部分一起使用,则将提升为双精度)放入%xmm0。第一个“正常整数类”类型的参数将进入%rdi。对于printf,指向格式字符串的指针是该类别的第一个参数,因此它会进入%rdi。这意味着传递的第一个整数参数进入该类别的第二个寄存器,即%rsi。因此,在printf(“%f”,1)中,printf会查找%xmm0中的浮点值,但调用者在%rsi中放置了整数1。printf("%f", 1);
会导致未定义的行为,因为它期望的是一个 double
类型的参数,但你传递了一个 int
。由于行为是未定义的,所以没有任何解释可以说明为什么会输出 0.0
。
%f
时,它会尝试将堆栈上相应部分的内存解释为浮点数。它无法知道编译器在此之前推送了int值。因此,printf尽力将内存解释为浮点数。结果取决于平台,即端序和浮点/整数大小,并且包括随机性,因为您很可能会碰到一些堆栈上的垃圾。在这种情况下,printf所做的转换也可以看作是这样的:int i = 1; // Integer variable
int* pi = &i; // Pointer to i
float* pf = (float*)pi; // Reinterpret the pointer as floating point number address
float f = *pf; // Get the floating point from this address
printf("%f\n", f);
int
都不会被放入堆栈中。字符串的第一个字符的指针被放入一个寄存器中,而int
则被放入另一个寄存器中。如果传递的是double
而不是int
1,则会将其放入完全不同的寄存器中。这样做的结果是,当printf
查找%f
的double
时,它看不到int
1的字节。它看到的是另一个寄存器中的字节。 - Eric Postpischil并非所有编译器都像这样,有些实际上会打印1.0。但是当指示printf打印双精度值时,必须传递一个双精度值,而不是整数。您可以始终使用类型转换:
printf("%f", (double)1);
printf("%f", 1);
时输出“1.0”吗? - Eric Postpischil在这里,printf()
期望接收基于您传递的格式的浮点数,如果要将int作为float在printf()
中打印,则需要进行强制转换。
printf("%f", (float)1);
or
printf("%f",(double)1);
printf()
的变量,如果你传递了错误的值,那么就会导致未定义的行为。
int
的字节将被printf
解释为浮点数。在一些常见的 C 实现中,特别是使用 System V x86-64 ABI 的实现中,第一个double
参数会被传递到%xmm0
寄存器中,而在格式字符串后传递给printf
的int
参数会被传递到%rsi
中。在处理%f
时,printf
将看到%xmm0
中的字节,而不是%rsi
中的字节。 - Eric Postpischildouble
参数(或者float
参数,如果与函数的...
部分一起使用,则会提升为double
)被放置在%xmm0
中。第一个“普通整数类”类型的参数将进入%rdi
。对于printf
来说,指向格式字符串的指针是该类别的第一个参数,因此它进入%rdi
。这意味着传递的第一个int
参数进入该类别的第二个寄存器,即%rsi
。因此,对于printf("%f", 1);
,printf
在%xmm0
中查找浮点值,但调用者在%rsi
中放置了一个int
1。 - Eric Postpischil