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值作为相应的参数。 否则行为是未定义的 ,这意味着您的计算机可能会崩溃或外星人可能敲门。 类似于%fdouble

是。 参数从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

与我的问题有关的东西。 支持马修的答案。