【问题标题】:What will be its output and why?它的输出是什么,为什么?
【发布时间】:2014-09-19 05:22:12
【问题描述】:

我正在检查范围规则问题,然后得到一个代码 sn-p,如下:

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

【问题讨论】:

  • 我的假设是因为printf使用vargs,并期望%d作为float y,它读取float的前4个字节为0,并留下后4个字节到下一个 %d 即 z,因此 z 打印了一个未定义的值。
  • 这段代码和ideone中的例子不一样
  • -1 此代码完全有效,与您从中获取结果的 ideone 中的代码不同。 ideone 代码有 bug。
  • “我想,如果最里面的印是这样的”——我想,如果我在头顶切一个洞并倒入酸液……会发生什么?跨度>
  • "此代码与 ideone 中的示例不同。" ——阅读理解?问题包含更改。 “这是你在 ideone 上的代码”——不,那是修改前的代码。

标签: c


【解决方案1】:

x、y 和 z 被解析为大多数本地定义。

当您使用不正确的 printf % 说明符时,行为未定义。

y 是浮点数,但您正在使用 %d 打印它(在后面的行中)。

printf 使用可变参数,一旦你使用不正确的说明符(在这种情况下是 %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 返回。

但永远不要依赖于此,并且始终编写行为明确的代码。

【讨论】:

  • 我认为是这样,至少看看问题中的代码,printf 格式字符串看起来还可以。您实际上是指链接中的代码吗?顺便说一句,这是关于 ideone 问题的代码:ideone.com/k6TCB7
  • 问题中I thought, what if the innermost print was this:之后的代码。
  • 好的,这个问题还不清楚。出于这个原因,我将反对票改为赞成票。
  • @JimBalter 我看到 3 或 4 次反对票,惊慌失措并删除了我的答案,但没有发现任何问题。所以我取消了答案并添加了更多信息。
【解决方案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.

【讨论】:

    【解决方案3】:

    z = 1077149696
    使用 %d 打印浮点值是未定义的行为。
    请改用“%f”

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

    总结一下: 自动变量在声明它们的块中是本地的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-13
      • 2019-02-06
      • 1970-01-01
      • 2022-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-16
      相关资源
      最近更新 更多