请考虑以下代码段
float a=12.2;
printf("%f %d",a,a); //output 12.200000 Garbage value
但是
printf("%d %f",a,a);//Output Garbage value Garbage Value
我的问题是为什么在第二个printf中,%d和%f都给出了垃圾值。我知道这是因为我先用了%d?但是找不到合适的解释..
答案 0 :(得分:4)
对数据类型使用错误的转换说明符会调用undefined behavior。您可能得到任何预期或意外结果。
如果转换规范无效,则行为未定义.282)如果有任何参数 不是相应转换规范的正确类型,行为是 未定义。
使用%d
打印a
(float
)的值会导致程序的未定义行为。
答案 1 :(得分:2)
当您在printf
中使用错误的说明符时,可能会发生以下情况。
来电者这样做:
float
参数将转换为double
。printf("%d %f"), a, a)
,调用者首先将最后一个a
放在堆栈上。调用者通过将堆栈指针更改为92,将a
转换为double
,并将8个字节写入堆栈,从而产生8个字节的空间。a
,调用者将堆栈指针更改为84并将八个字节写入堆栈。"%d %f"
,调用者将堆栈指针更改为80并将四字节指针写入堆栈。然后printf
执行此操作:
printf
初始化一个指向参数开始位置的指针,80。printf
将其参数指针更新为指向84。%d
,因此printf
需要一个四字节整数,它从84开始读取四个字节。int
是四个字节,printf
将其参数指针更新为指向88. double
的编码,因此从84到87的四个字节没有任何意义int
,printf
打印任何内容这些位碰巧代表int
值。%f
,因此printf
需要一个8字节的double
,它从88开始读取8个字节。double
末尾的四个字节和第二个double
开头的四个字节,所以它们没有任何意义{{1 }和double
打印出比特碰巧代表的任何值。这不是所有C实现的工作方式,但是当您使用printf
的错误参数时,可能会发生一件事。 C标准使行为未定义,因为它不控制实现的工作方式,因此它们的行为可能如上所述,但它们可能会在寄存器中传递一些参数。在后一种情况下,您会看到不同的行为,例如printf
为printf
打印垃圾,因为没有任何东西将相应的整数寄存器设置为适当的值,但%d
打印{的正确值{1}}因为它在浮点寄存器中查找它,并且调用者确实将printf
的值放在浮点寄存器中。
答案 2 :(得分:1)
因为你不知道会发生什么。如果sizeof(float) != sizeof(int)
,在第二种情况下肯定会得到两次垃圾值,因为printf
从第一个参数读取太多字节或太少字节,所以在读取下一个参数时会搞砸(假设参数在堆栈上传递)。
出现的另一个问题是传递的参数被转换为double
,通常的大小与int
不同,然后printf
次尝试从int
的内容中选择double
。尺寸不匹配(请参阅下面的评论)。
无论哪种方式,这都会调用未定义的行为,所以你真的无法“期待”任何有意义的事情发生。