2010-08-01 178 views
4
#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); 
} 

输出:printf()取决于格式说明符的顺序吗?

0 
0.000000 
0.500000 
0 

编译用gcc 4.4.3 程序,错误代码退出12

+0

*现在* *很有趣... – dmckee 2010-08-01 19:34:39

+2

我有一种冲动来解决这个问题 - 只是在字符串的开头使用“\ n”。否则,这就是为什么始终保持编译器警告激活的好主意。 – Dummy00001 2010-08-01 19:48:57

+0

@Dummy:同意换行符,但是我一直无法得到'gcc'来抱怨任何接受'main'缺少正确指定的返回类型的东西。 – dmckee 2010-08-01 19:51:39

回答

15

正如在其他答案中指出的,这是因为格式字符串和参数类型之间的不匹配。

我猜你在这里使用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的,所以它似乎工作。

2

该结果并不令人惊讶,在第一%d你通过一个双其中一个整数预计。

+0

+1首先回答。 – 2010-08-01 19:36:48

+1

@Billy ONeal,我以为你应该upvote正确的答案... – strager 2010-08-01 19:37:23

+0

@Strager:他们都是正确的答案;我把所有这些都提高了。只是想不出别的理由。 – 2010-08-01 19:38:51

4

是的。参数从可变参数列表中读取,与读取格式说明符的顺序相同。

这两个printf语句都是无效的,因为您使用的格式说明符预期为int,但您只给它一个 float double。

+0

但是为什么它的行为在两个陈述中都会改变? – blacktooth 2010-08-01 19:41:35

+4

@blacktooth:不知道。当你调用未定义的行为时,编译器不需要做明智的事情。 – 2010-08-01 19:46:27

+0

@比利我告诉那个问我同样问题的人。 :D他告诉我这是一个面试问题! – blacktooth 2010-08-01 19:49:00

7

当你说在格式化字符串%d,你必须通过int值作为相应的参数。否则的行为是不确定的,这意味着你的电脑可能会崩溃或外星人可能敲你的门。类似于%fdouble

+1

生活学会了我总是投这样的所有printf参数: const char * p =“stop”; int i = 7; printf(“Hello%s%d”,(const char *)p,(int)i); – danatel 2010-08-01 19:50:06

+0

这也很危险。我宁愿放弃这些强制转换,让编译器检查这些类型是否匹配。 GCC在这方面做得非常出色。在C中,你永远不能确定'(const char *)'不会意外地将一个'int'转换为一个指针。从句法上讲,这是可能的。 – 2010-08-01 20:56:09

3

你在做什么是不确定行为。你看到的是巧合的; printf可以写任何东西。

在给出printf参数时,您必须匹配确切类型。你可以例如演员:

printf("\n%d\n%f", (int)(x/y), x/y); 
printf("\n%f\n%d", x/y, (int)(x/y));