它的输出是什么?为什么?

时间:2014-09-19 05:22:13

标签: c

我正在查看范围规则问题以及所有内容,然后获得了一个代码段,如下所示:

#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打印那个值吗?

3 个答案:

答案 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”代替

  1. 您使用的所有变量都有存储类型“自动”或“自动”。
  2. 自动变量的范围位于声明它的块内。
  3. 如果存在嵌套块,则在最外面的块中声明的变量将对所有其他块可见。
  4. 如果一个块有一个声明的变量与外部块中声明的变量匹配,那么它将覆盖外部变量“在其块中”,即(本地)。
  5. 总结: 自动变量是声明它们的块的本地变量。