printf()是否依赖于格式说明符的顺序?

时间:2010-08-01 19:30:00

标签: c floating-point double printf

#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

6 个答案:

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

答案 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

与我的问题有关的事情。支持马修的答案。