【问题标题】:C++ functions and scope of variablesC++ 函数和变量范围
【发布时间】:2018-02-15 16:38:23
【问题描述】:
#include<iostream>

using namespace std;

void fun(int a) {
    int x;
    cout << x << endl;
    x = a;
}

int main() {
    fun(12);
    fun(1);
    return 0;
}

这段代码的输出如下:

178293 //garbage value
12

为什么我们得到12 而不是垃圾值??

【问题讨论】:

  • 那些玩弄未初始化变量和未定义行为的人注定要受苦。
  • 当你cout&lt;&lt;x&lt;&lt;endl;x的值是多少?? (也许将x=a;移到函数顶部??)
  • 12 是一个垃圾值(其中之一)
  • 这是未定义的行为。第二次的垃圾值恰好是 12。
  • 12 与任何其他值一样垃圾。在两者之间调用另一个使用堆栈的函数,您可能会看到其他内容。仅仅因为它是您所期望的,并不意味着它是正确的

标签: c++ function scope


【解决方案1】:

为什么我们得到 12 而不是垃圾值??

理论上,x 的值可以是任何值。然而,实际情况是,对fun 的两次调用一个接一个地导致x 的先前值仍在堆栈帧上。

假设堆栈帧的结构如下:

 arguments
 return value
 local variables

在你的情况下,

用于参数的内存等于sizeof(int)
由于返回类型为void,编译器可能会省略使用任何内存作为返回值。
用于局部变量的内存等于sizeof(int)

第一次调用函数时,参数部分的值设置为 12。正如您所注意到的,局部变量中的值是垃圾。但是,在从函数返回之前,将局部变量的值设置为 12。

第二次创建函数时,参数的值被设置为1。局部变量中的值仍然是上次调用时遗留下来的。因此,它仍然是 12。如果您第三次调用该函数,您可能会在局部变量中看到值 1。

无论如何,这是一个合理的解释。再一次记住,这是未定义的行为。不要指望任何特定的行为。编译器可以决定在使用堆栈帧之前对其进行清理。编译器可以决定在堆栈帧被使用后立即对其进行清理。编译器可以在使用堆栈帧后对其执行任何操作。如果在对 fun 的调用之间有另一个调用,您很可能会得到完全不同的值。

【讨论】:

  • 堆栈帧可能会在程序执行前两千万年被丢弃到黑洞中。
【解决方案2】:

打印时您还没有初始化值x。从未初始化的内存中读取是 UB,,不能保证会发生什么。它可能会输出一个随机数,或者调用一个不太可能的位组合,从而做出意想不到的事情。

【讨论】:

    【解决方案3】:

    读取一个未初始化的整数是UNDEFINED BEHAVIOR,这意味着它可以做任何事情,可以打印任何东西。它可以格式化您的硬盘驱动器或崩溃可观察的宇宙!基本上我不知道这样做的编译器实现,但理论上它们可以!

    【讨论】:

    • 你永远不知道!
    猜你喜欢
    • 1970-01-01
    • 2015-08-25
    • 1970-01-01
    • 1970-01-01
    • 2020-07-22
    • 2021-12-18
    • 2013-10-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多