2011-11-20 86 views
2

我在windows7上使用dev cpp编译我的代码。将int打印为float时,printf的行为是什么?

int d = 0x12; 
char* e = (char*)&d; 
printf("%d %d\n", sizeof (int), sizeof (float)); 
printf("%p %p\n", &d, (float*)&d); 
printf("%p %p %p %p %p\n", &d, &e[0], &e[1], &e[2], &e[3]); 
printf(" %d | %x | %#1x | %#1x | %#1x |%p\n", d, e[0], e[1], e[2], e[3], &e[0]); 
getchar(); 

4 4 
0028FF40 0028FF40 
0028FF40 0028FF40 0028FF41 0028FF42 0028FF43 
18 | 12 | 0 | 0 | 0 |0028FF40 

你可以看到,如果我使用%d打印d,它会打印e的4个字节。但是如果我使用下面的%f,它会在必须打印e的第一个字节的地方显示零。任何人都可以帮助解释为何发生这种情况为什么e的内容取决于d如何格式化?

int d = 0x12; 
char* e = (char*)&d; 
printf("%d %d\n", sizeof (int), sizeof (float)); 
printf("%p %p\n", &d, (float*)&d); 
printf("%p %p %p %p %p\n", &d, &e[0], &e[1], &e[2], &e[3]); 
printf(" %f | %x | %#1x | %#1x | %#1x |%p\n", d, e[0], e[1], e[2], e[3], &e[0]); 
getchar(); 

的输出是:

4 4 
0028FF40 0028FF40 
0028FF40 0028FF40 0028FF41 0028FF42 0028FF43 
0.000000 | 0 | 0 | 0 | 0x28ff40 |76869F1D 
+3

您应该停止使用Dev-Cpp。它非常过时,并使用古代版本的GCC。 – ThiefMaster

+0

为什么你将'(int *)'转换为'(float *)'?编程很难,因为它没有这样的东西。 –

+0

[如果printf被错误的格式字符串调用会发生什么?](http:// stackoverflow。com/questions/14504148/what-c​​an-happen-if-printf-is-called-with-a-wrong-format-string) –

回答

8

未定义的行为。

在实践中,你看到的可能是由于这样的事实,%f使得printf从参数列表,这是8个字节*double。但d只有4个字节大小,所以现在一切都没有对齐。

请记住,printf是一个可变参数函数,这意味着它是完全非类型安全的; printf必须在没有编译器帮助的情况下从堆栈中提取原始字节。完全取决于您确保参数与格式字符串完全对应。


*可能。

+0

我认为你的答案意味着e的字节仍然存在,但它只是它从错误的地方读取它们。我可以通过在下一行中制作一个铸造的printf来进行验证。 printf(“%f |%x |%#1x |%#1x |%#1x |%p \ n”,(float)d,e [0],e [1],e [2],e [3 ],&e[0]); 这实际上给出了正确的结果。感谢您的解释。 – ada

1

是的,你正在从堆栈中取出8个字节 - 其中四个是0x00000012,其余依赖于编译器(可能是在构建printf的堆栈帧时被压入堆栈的返回地址)。

2

您正在通过自动类型促销绊倒。

您似乎认为自sizeof(int)== sizeof(float)以来,您可以将d作为float或int交替传递。但事情是,在C中你不能传递一个浮点数。

在C中,当在表达式中使用char或short时,它会自动转换为int。同样,当您在表达式中使用float时,它会自动转换为double。

因此,当您执行printf(“%f”,d)时,编译器会在进行函数调用之前将一个int,即四个字节推入堆栈。然后在函数中,printf()看到“%f”,并从堆栈中取出八个字节。其中四个字节是你的“d”,另外四个字节是在那里发生的。在你的例子中,e [0]和e [1]。

如果要将“d”打印为浮点数,则需要明确地将其转换为浮点型变量或将其分配给浮点型变量。无论哪种情况,编译器都会在调用printf()之前将其转换为double。 (注意:听起来很奇怪,“%f”用于打印双精度数据,而不是浮点数,不能打印浮点数,可以用“%f”和“%lf”来读浮点数或双精度浮点数。 scanf(),但在printf()中,“%f”打印双打。)

+0

informative thanks。:) – ada

+0

*“当您在表达式中使用float时,它会自动转换为double。”*这是错误的。除非表达式中的其他操作数是双精度(*常用算术转换*),否则浮点不会在所有表达式中隐式转换为double。你所追求的是什么*默认参数促销*,只有当A)float被传递给没有原型的函数时,才会发生** B)float被传递给带有可变参数的函数(原型以',..结尾.. .. .')。 – user694733

相关问题