printf()是否依赖于格式说明符的顺序?
#include 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
传递给varargs函数(由于类型为“promotion”规则)。
int
是32位值, double
是64位值。
在这两种情况下,您都要传递x/y
(= 0.5)两次。 此值的表示forms为64位double
0x3fe0000000000000
,为0x3fe0000000000000
。 作为一对32位字,它存储为0x00000000
(最低有效32位),然后是0x3fe00000
(最高有效32位)。 所以printf()
看到的栈上的参数如下所示:
0x3fe00000 0x00000000 0x3fe00000 0x00000000 <-- stack pointer
在两种情况的第一种情况下, %d
会弹出并打印第一个32位值0x00000000
。 %f
弹出接下来的两个32位值, 0x3fe00000
(64位double
0x3fe00000
最低32位),然后是0x00000000
(最重要)。 得到的64位值0x000000003fe00000
(解释为double
)是一个非常小的数字。 (如果将格式字符串中的%f
更改为%g
您将看到它几乎为0,但不完全相同)。
在第二种情况下, %f
正确弹出第一个double
0x00000000
数, %d
弹出第二个double
0x00000000
一半0x00000000
,因此它似乎可以正常工作。
当您在printf格式字符串中说%d
时, 必须传递一个int
值作为相应的参数。 否则行为是未定义的 ,这意味着您的计算机可能会崩溃或外星人可能敲门。 类似于%f
和double
。
是。 参数从vararg列表读取到printf的顺序与读取格式说明符的顺序相同。
这两个printf
语句都是无效的,因为你正在使用一个期望int的格式说明符,但你只给它一个float double。
你在做什么是不端行为。 你所看到的是巧合; printf
可以写任何东西。
在给出printf
参数时,您必须匹配确切的类型。 你可以举例如:
printf("\n%d\n%f", (int)(x/y), x/y); printf("\n%f\n%d", x/y, (int)(x/y));
这个结果并不奇怪,在第一个%d中,你传递了一个预期整数的double。
http://en.wikipedia.org/wiki/Format_string_attack
与我的问题有关的东西。 支持马修的答案。