#include<stdio.h>
main()
{
float x=2;
float y=4;
printf("\n%d\n%f",x/y,x/y);
printf("\n%f\n%d",x/y,x/y);
}
0
0.000000
0.500000
0
编译用gcc 4.4.3 程序,错误代码退出12
#include<stdio.h>
main()
{
float x=2;
float y=4;
printf("\n%d\n%f",x/y,x/y);
printf("\n%f\n%d",x/y,x/y);
}
0
0.000000
0.500000
0
编译用gcc 4.4.3 程序,错误代码退出12
正如在其他答案中指出的,这是因为格式字符串和参数类型之间的不匹配。
我猜你在这里使用x86(根据观察结果)。
参数在栈上传递,而x/y
(尽管类型为float
)将作为double
传递给可变参数函数(由于类型“提升”规则)。
int
是一个32位的值,而double
是一个64位的值。
在这两种情况下,您都通过x/y
(= 0.5)两次。该值的表示形式为64位double
,为0x3fe0000000000000
。作为一对32位字,它被存储为0x00000000
(最不重要的32位),然后是0x3fe00000
(最重要的32位)。因此,在栈上的参数会被printf()
所看到,像这样:
0x3fe00000
0x00000000
0x3fe00000
0x00000000 <-- stack pointer
在第一个你的两种情况,%d
导致第一个32位的值,0x00000000
,被弹出并打印。 %f
弹出接下来的两个32位值,0x3fe00000
(64位double
的最低有效32位),然后是0x00000000
(最重要)。结果为0x000000003fe00000
的64位值,解释为double
,是一个非常小的数字。 (如果将格式字符串中的%f
更改为%g
,则会看到它几乎为0,但不完全)。
在第二种情况下,%f
正确弹出第一double
,和%d
弹出0x00000000
一半的第二double
的,所以它似乎工作。
该结果并不令人惊讶,在第一%d你通过一个双其中一个整数预计。
+1首先回答。 – 2010-08-01 19:36:48
@Billy ONeal,我以为你应该upvote正确的答案... – strager 2010-08-01 19:37:23
@Strager:他们都是正确的答案;我把所有这些都提高了。只是想不出别的理由。 – 2010-08-01 19:38:51
是的。参数从可变参数列表中读取,与读取格式说明符的顺序相同。
这两个printf
语句都是无效的,因为您使用的格式说明符预期为int,但您只给它一个 float double。
但是为什么它的行为在两个陈述中都会改变? – blacktooth 2010-08-01 19:41:35
@blacktooth:不知道。当你调用未定义的行为时,编译器不需要做明智的事情。 – 2010-08-01 19:46:27
@比利我告诉那个问我同样问题的人。 :D他告诉我这是一个面试问题! – blacktooth 2010-08-01 19:49:00
当你说在格式化字符串%d
,你必须通过的int
值作为相应的参数。否则的行为是不确定的,这意味着你的电脑可能会崩溃或外星人可能敲你的门。类似于%f
和double
。
生活学会了我总是投这样的所有printf参数: const char * p =“stop”; int i = 7; printf(“Hello%s%d”,(const char *)p,(int)i); – danatel 2010-08-01 19:50:06
这也很危险。我宁愿放弃这些强制转换,让编译器检查这些类型是否匹配。 GCC在这方面做得非常出色。在C中,你永远不能确定'(const char *)'不会意外地将一个'int'转换为一个指针。从句法上讲,这是可能的。 – 2010-08-01 20:56:09
你在做什么是不确定行为。你看到的是巧合的; printf
可以写任何东西。
在给出printf
参数时,您必须匹配确切类型。你可以例如演员:
printf("\n%d\n%f", (int)(x/y), x/y);
printf("\n%f\n%d", x/y, (int)(x/y));
http://en.wikipedia.org/wiki/Format_string_attack
东西与我的问题。支持马修的回答。
*现在* *很有趣... – dmckee 2010-08-01 19:34:39
我有一种冲动来解决这个问题 - 只是在字符串的开头使用“\ n”。否则,这就是为什么始终保持编译器警告激活的好主意。 – Dummy00001 2010-08-01 19:48:57
@Dummy:同意换行符,但是我一直无法得到'gcc'来抱怨任何接受'main'缺少正确指定的返回类型的东西。 – dmckee 2010-08-01 19:51:39