传递的局部变量 (C++)

Local Variables Being Passed ( C++)

我在学习C++的过程中遇到了一个问题,一个函数中的局部变量被传递给另一个函数中同名的局部变量,这两个函数运行在main( ).

当这是运行,

#include <iostream>
using namespace std;

void next();
void again();

int main()
{
    int a = 2;
    cout << a << endl;
    next();
    again();
    return 0;
}

void next()
{
    int a = 5;
    cout << a << endl;
}

void again()
{
    int a;
    cout << a << endl;
}

它输出:

2
5
5

我预计 again() 会说 null 或 0,因为 'a' 在那里再次声明,但它似乎使用了 'a' 在 next() 中分配的值。

为什么在again()中再次声明了'a',next()会将局部变量'a'的值传递给again()?

这完全是巧合和未定义的行为。

发生的事情是您有两个函数紧接着调用。两者将具有或多或少相同的函数序言,并且都在堆栈上保留一个大小完全相同的变量。

由于在播放中没有其他变量并且堆栈在调用之间没有被修改,所以您恰好在第二个函数 "landing" 中的局部变量与前一个函数的位置相同局部变量。

显然,这不是一个好依靠。事实上,这是一个完美的例子,说明为什么你应该 总是 初始化变量!

*内置类型的未初始化非static局部变量(呸!那是一口)有一个不确定值。除了 char 类型外,使用该值会正式产生 Undefined Behavior、a.k.a。 UB。任何事情都可能发生,包括您看到的行为。

显然,使用您的编译器和选项,在 next 的调用中用于 a 的堆栈区域在 again 的调用之前未用于其他用途,它在 again 中被重新用于 a,现在具有与以前相同的值。

但你不能依赖它。有了 UB,一切皆有可能。


* 或者更一般的 POD 类型,Plain Old Data。标准对此的规范有些复杂。在 C++11 中,它以 §8.5/11 开头,“如果没有为对象指定初始化器,则该对象被默认初始化;如果未执行初始化,则具有自动或动态存储持续时间的对象具有不确定的值。”。其中“automatic … storage duration”包括局部非static变量的情况。并且“无初始化”可以通过定义默认初始化的 §8.5/6 以两种方式发生,即通过不执行任何操作的默认构造函数,或者通过对象不是 class 或数组类型。

http://en.cppreference.com/w/cpp/language/ub

你是对的,未初始化的变量是禁忌。但是,您可以先声明一个变量,然后再对其进行初始化。内存被预留用于保存整数,但是在您这样做之前,该内存中恰好有什么值可以是任何值。有些编译器会将变量自动初始化为垃圾值(以帮助您捕获错误),有些会自动初始化为默认值,有些则什么都不做。 C++ 本身没有任何承诺,因此它是未定义的行为。在您的情况下,使用您的简单程序,很容易想象编译器如何创建汇编代码来重用完全相同的内存而不改变它。然而,这是盲目的运气,即使在您的简单程序中也不能保证会发生。这些类型的错误实际上可能相当隐蔽,因此请定下一条规则:警惕未初始化的变量。