#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
答案 0 :(得分:15)
正如其他答案所述,这是因为格式字符串与参数类型不匹配。
我猜你在这里使用的是x86(基于观察到的结果)。
参数在堆栈上传递,x/y
虽然类型为float
,但会作为double
传递给varargs函数(由于类型为“促销”规则)
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
(最重要)。得到的64位值0x000000003fe00000
被解释为double
,是一个非常小的数字。 (如果您将格式字符串中的%f
更改为%g
,您会看到它几乎为0,但不完全是。
在第二种情况下,%f
正确弹出第一个double
,%d
弹出0x00000000
第二个double
的一半,所以它似乎工作。
答案 1 :(得分:7)
当您在printf格式字符串中说%d
时,必须传递int
值作为相应的参数。否则行为未定义,这意味着您的计算机可能会崩溃或外星人可能会敲门。类似于%f
和double
。
答案 2 :(得分:4)
是。参数从vararg列表读取到printf的顺序与读取格式说明符的顺序相同。
两个printf
语句都是无效的,因为你正在使用一个期望int的格式说明符,但你只给它一个 float double。
答案 3 :(得分:3)
你在做什么是不端行为。你所看到的是巧合; printf
可以写任何东西。
在提供printf
参数时,您必须匹配确切的类型。你可以,例如投:
printf("\n%d\n%f", (int)(x/y), x/y);
printf("\n%f\n%d", x/y, (int)(x/y));
答案 4 :(得分:2)
这个结果并不奇怪,在第一个%d中你传递了一个预期整数的double。
答案 5 :(得分:0)
http://en.wikipedia.org/wiki/Format_string_attack
与我的问题有关的事情。支持马修的答案。