#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int x, *ptr_x;
float f , *ptr_f;
ptr_f = &f;
ptr_x = &x;
*ptr_x = 5;
*ptr_f = 1.5; //printf("%d %f\n", f,x);
printf ("\n\nxd = %d \t xf = %f \n ff = %f \t fd = %d", x,x,f,f);
return 0;
}
不期望ff =%f的输出。
xd = 5 xf = 0.000000
ff = 0.000000 fd = 1073217536
的
此代码的要点是显示如果使用%d打印浮动值并且打印的值为%f,将会发生什么。
为什么即使我使用%f?
,浮点值也无法正确打印答案 0 :(得分:15)
printf()不是类型安全的。
您传递给printf()
的参数将根据您承诺编译器的内容来处理。
此外,float
在通过可变参数传递时会被提升为double
。
因此,当您第一次(%f
)承诺编译器xf
时,编译器会从参数中吞噬整个double
(通常为8个字节),吞噬您的浮点数这个过程。然后第二个%f
切入第二个双尾的零尾数。
这是你的论点的图片:
+-0-1-2-3-+-0-1-2-3-+-0-1-2-3-4-5-6-7-+-0-1-2-3-4-5-6-7-+
| x | x | f | f |
+---------+---------+-----------------+-----------------+
%d--------|%f----------------|%f---------------|%d------|
但是f
看起来像这样(已被提升为double
):
f = 3FF8000000000000
让我们再次使用值绘制它,并推测您的机器字节序:
| 05000000 | 05000000 | 00000000 0000F83F | 00000000 0000F83F |
| %d, OK | %f, denormal... | %f, denormal... | %d, OK |
请注意,1073217536是0x3FF80000。
答案 1 :(得分:3)
将至少一个无效格式说明符传递给printf
后(例如尝试使用float
或%d
打印int
值值%f
)你的整个程序搞砸了无法修复。这种破坏性行动的后果可以在计划的任何地方看到。在您的情况下,尝试使用无效的格式说明符打印某些内容会导致即使有效的格式说明符停止工作。
正式地说,你写了一个展示未定义行为的程序。它可以完全无法预测。你自己说了
此代码的要点是显示浮动时会发生什么 使用%d打印值,如果打印int值,则打印%f。
您观察到的破碎行为正好表明了这一点!当您尝试做类似的事情时,会发生一个奇怪且无法预测的表演程序。
答案 2 :(得分:0)
试试这个:
printf("size of int = %d, size of float = %d, size of double = %d\n",
sizeof(int), sizeof(float), sizeof(double));
当您调用printf()
时,系统会将参数压入堆栈。所以堆栈看起来像这样:
pointer to format string [probably 4 bytes]
x [probably 4 bytes]
x [probably 4 bytes]
f [probably 6 or 8 bytes]
f [probably 6 or 8 bytes]
然后printf()
在解析格式字符串时从堆栈中弹出字节。当它看到%d
时,它会为int弹出足够的字节,当它看到%f
时,它会为浮点弹出足够的字节。 (实际上,当浮点数作为函数参数传递时,它们被提升为双精度数,但重要的是它们需要更多的字节而不是整数。)因此,如果你对参数“撒谎”它会弹出错误的字节数并盲目地根据您的指示转换它们。
因此,它会首先为xd
弹出正确的字节数,因为你已经正确地告诉它x是一个int。
但是它会弹出足够的字节用于浮点数,它会消耗堆栈中第二个x
和第一个f
的一部分,并将它们解释为xf
的浮点数
然后它将为另一个浮点数弹出足够的字节,这将消耗第一个f
的剩余部分和第二个f
的一部分,并将它们解释为ff
的浮点数
最后,它将为int弹出足够的字节,这将占用第二个f
的剩余部分,并将它们解释为fd
的int。
希望有所帮助。