我正在研究两个代码段的有趣行为,这给了我意想不到的行为。
描述行为
代码段1:#include <iostream>
using namespace std;
int main()
{
long long n;
long long m;
// cin >> n;
cout << m;
return 0;
}
当我运行这个(例如在https://www.onlinegdb.com/online_c++_compiler中)时,在控制台中打印的值(变量m
中的值)是0。这是预期的,并且对应于long long
类型的默认初始化为0(零初始化)的事实。
#include <iostream>
using namespace std;
int main()
{
long long n;
long long m;
cin >> n;
cout << m;
return 0;
}
通过用cin取消注释行并添加任何值,我不会得到0,而是根据我输入的n
的数字获得不同的值。此行为的其他特征有:
- 对于不同的
n
输入值,我们得到不同的m
值。 - 每次
n
给定相同的值,m
也得到相同的值。 - 定义
n
或m
static结果是预期的行为,即m
携带值0。 - 如果
m
,n
是int
s,同样的行为仍然存在
意外的行为是m
没有默认初始化为0。
- 未注释的
cin >> n
行创建一个新线程执行。 - 新线程创建一个新的堆栈,所有的局部变量都被复制到这个堆栈中。
- 由于
m
没有在原始堆栈中初始化,因此它携带的值在新堆栈中是不确定的。它取决于当前堆栈的状态。但是堆栈的状态取决于原始复制堆栈的状态,而原始复制堆栈的状态又取决于输入n
的值。
c++初始化是超级复杂。然而,这种情况相当简单(抛开令人困惑的术语;)。您是对的,m
和n
都是默认初始化的。不过,紧接着你的解释就错了。它以
这是预期的,并且对应于long long类型的默认初始化为0(零初始化)。
long long int
的默认初始化是而不是零初始化。实际上它根本没有初始化。从cppreference:
在三种情况下执行默认初始化:
- 当声明具有自动、静态或线程本地存储持续时间的变量而没有初始化时;
[…]
和
默认初始化的效果如下:
- 如果T是一个非pod(直到c++ 11)类类型,[…]
long long
不是类类型…]- 如果T是数组类型,[…][
long long
不是数组类型]- 否则,不进行初始化:具有自动存储持续时间的对象(及其子对象)包含不确定的值。
读取不确定的值是未定义行为。添加或删除看似不相关的代码行来改变输出是未定义行为的典型影响。代码的输出可以是任何东西。