【问题标题】:Why does std:endl assign zero to an unitialized variable? [duplicate]为什么 std:endl 将零分配给未初始化的变量? [复制]
【发布时间】:2023-03-07 16:42:01
【问题描述】:

请考虑以下 C++ sn-p:

#include <iostream>

int main() {
    int x;
    std::cout << x << '\n';
    return 0;
}

正如预期的那样,由于变量x 尚未初始化,因此打印的结果将是不可预测的。如果你运行它可能会得到 458785234 和 348934610 第二次。但是,如果您按以下方式更改代码:

#include <iostream>

int main() {
    int x;
    std::cout << x << std::endl;
    return 0;
}

现在,打印的 x 始终等于 0。这是为什么?请注意,引入的唯一更改是std::endl。谁能解释为什么这会将 0 分配给 x 变量?

【问题讨论】:

  • x 未初始化。你不应该对它的价值抱有任何期望。 (严格来说,这是U.B.。)所以,答案可能是“为什么不”。 ;-)
  • “现在,打印的 x 始终等于 0。” 仅在您测试过的情况下。这是未定义的行为,因此它在其他平台、其他编译器或没有明显原因的情况下可能会有所不同。
  • 尝试用一个值初始化x。例如int x = 1
  • 很有趣(只要查看未定义的行为很有趣)。生成的程序集告诉你什么关于它总是在第二种情况下为零?
  • 对于“为什么我的未定义行为未定义”问题是否存在通用重复项?

标签: c++ g++ std


【解决方案1】:

正如预期的那样,打印的结果将是不可预测的......

现在,打印的 x 始终等于 0。这是为什么呢?

之所以如此,是因为行为未定义。

您预计该数字是“不可预测的”。看来您没有预测数字为零。这应该符合您的期望。

你没有做任何事情来使这个数字非零,那么你为什么期望这个数字非零呢?

另一方面,您可能一直期望行为不会改变,因为对程序的更改似乎无关紧要。这种期望是不明智的。如果您更改程序的任何部分,未定义的行为不能保证是相同的未定义行为。实际上,即使您不进行任何更改,也不能保证行为相同。另一方面,也不保证行为会有所不同。对程序的行为没有任何保证。这就是未定义行为的含义。

【讨论】:

  • 谢谢!我的问题背后的意图是找到导致 x 为 0 的机制。我正在努力学习和编写快速程序,所以我需要了解它是如何设置的所有细节。
  • @user3732445 我怀疑关于编写快速程序有什么要学习的。
【解决方案2】:

在 Ubuntu 16.04 上使用 gcc 5.4.0,我在两个版本的代码中都得到了 0。但这并不重要,因为 x 未初始化并且试图读取它是未定义的行为。任何事情都可能发生,具体取决于所使用的特定编译器和系统,但不保证任何特定行为。

现在考虑以下几点:

#include <iostream>

void foo() {
    int x;
    std::cout << x << std::endl;
}

void bar() {
    int y = 123;
    std::cout << y << std::endl;
}

int main() {
    foo();
    bar();
    foo();

    return 0;
}

在我的机器上打印:

0
123
123

所以我的猜测是我的编译器在程序启动之前对堆栈区域进行了零初始化,但以后不会费心这样做以避免不必要的工作。

但正如我之前指出的,这些行为是未定义的。标准对此没有任何要求,因此我们不能假设任何特定的事情总是会发生。

【讨论】:

  • 是的,可能是编译器问题。因为在我的带有 g++(Apple LLVM 版本 10.0.0 (clang-1000.10.44.4))的 Mac 上,行为是不同的。
【解决方案3】:

你得到的是编译器调用,这是未定义的行为 使用 Microsfot Visual C++ 甚至无法编译(错误 C4700:使用了未初始化的局部变量 'x')

【讨论】:

    猜你喜欢
    • 2021-10-16
    • 2011-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多