我正在查看范围规则问题以及所有内容,然后获得了一个代码段,如下所示:
#include <stdio.h>
int main()
{
int x = 1, y = 2, z = 3;
printf(" x = %d, y = %d, z = %d \n", x, y, z);
{
int x = 10;
float y = 20;
printf(" x = %d, y = %f, z = %d \n", x, y, z);
{
int z = 100;
printf(" x = %d, y = %f, z = %d \n", x, y, z);
}
}
return 0;
}
如果我将最后一次打印更改为:
printf("x = %d, y = %d, z = %d \n", x, y, z);
我得到以下输出,我不明白:(Ideone link)
x = 10, y = 0, z = 1077149696
那么,你能解释为什么z打印那个值吗?
答案 0 :(得分:9)
x,y和z被解析为大多数本地定义。
使用不正确的printf%说明符时,行为未定义。
y是浮动的,但是您使用%d来打印它(在后面的行中)。
printf
使用varargs,一旦你通过使用不正确的说明符(在这种情况下%d而不是%f)来破坏堆栈,堆栈就会被破坏并且堆栈数据的错误解释(错误的偏移量)会导致很多痛苦惊喜。
解码此UB
这是你机器上可能发生的事情(一种可能的解释)。由于default argument promotion,位模式(十六进制)0x4034000000000000被推送到堆栈20.0f。您的little-endian机器上的sizeof int是4个字节。当你将float打印为int时,你的机器0x00000000被消耗并被解释为int,它打印第一0
,后来%d
消耗0x40340000将其解释为int并打印1077149696.最终100(0x00000064)留在堆栈中未消耗和printf返回。
但是永远不要依赖于此,并且总是编写一个行为定义良好的代码。
答案 1 :(得分:2)
@ mohit-jain是对的。
使用错误的格式说明符会在堆栈上产生错误的参数解释,从而导致未定义和编译器特定的行为。
请注意,在现代编译器(如gcc或clang)上,它会抱怨您的格式规范错误:
$ clang test.c
test.c:12:54: warning: format specifies type 'int' but the argument has type 'float'
[-Wformat]
printf(" x = %d, y = %d, z = %d \n", x, y, z);
~~ ^
%f
1 warning generated.
答案 2 :(得分:0)
z = 1077149696
使用%d打印浮点值是不确定的行为
使用“%f”代替
总结: 自动变量是声明它们的块的本地变量。