是否所有“真正的”C++ 编译器都没有内置类型为零的默认初始化?我在问'因为我发现了声称是 gcc 的在线编译器,它对内置类型进行零初始化
int h=6548;
for (int i; i < 10; ++i) {
cout<<i<<"\n";
}
对于这段代码,它的输出是
0
1
2
3
4
5
6
7
8
9
是否所有“真正的”C++ 编译器都没有内置类型为零的默认初始化?我在问'因为我发现了声称是 gcc 的在线编译器,它对内置类型进行零初始化
int h=6548;
for (int i; i < 10; ++i) {
cout<<i<<"\n";
}
对于这段代码,它的输出是
0
1
2
3
4
5
6
7
8
9
值是否被初始化取决于未定义的行为和实现。你不能依赖它。
如果没有为对象指定初始化器,则该对象是默认初始化的;如果不执行初始化,则具有自动或动态存储持续时间的对象具有不确定值。[ 注意:具有静态或线程存储持续时间的对象是零初始化的,请参见 3.6.2。——尾注]
如果你使用int i;
它会导致一个具有“不确定值”的未初始化整数!如果您访问它的价值,您无法预测会发生什么。
初始化器是一组空括号的对象,即 (),应进行值初始化。
如果你使用int i = int();
你有一个 value-initialized i
。现在,什么是值初始化?
对T 类型的对象进行值初始化意味着:
- [...](其中 T 可能是类或数组类型的一些选项)
- 否则,对象被零初始化。
好的,现在我们知道这int i = int();
意味着拥有i=0
.
请注意以下事项:
注意:由于初始化程序的语法不允许 (),
X a();
不是类 X 的值初始化对象的声明,而是一个不带参数并返回 X 的函数的声明。
强调标准报价是我的。
什么初始化。在您的示例中,访问i
是未定义的行为,因为它没有被初始化。一些编译器
确实会初始化它,至少在调试模式下,但通常使用类似0xDEADBEEF
or的东西0xCCCCCCCC
,以便您可以在调试器中轻松识别您正在访问未初始化的内存(并且如果您使用它,程序可能会崩溃)一个指针),但这不是必需的。
唯一一次隐式初始化内置类型是当它们具有静态存储持续时间时:在命名空间范围内定义的变量(包括静态类成员)或已声明的局部变量static
。
您没有显示代码的上下文,但如果它直接在 中main
,或者在第一个调用 from 的函数中main
,int i
将是第一次使用这个实际内存。出于安全原因,操作系统可能会将其设置为 0。您可能想尝试以下方法:
void scribble()
{
int x = 0x12345678;
}
void testit()
{
for ( int i; i < 10; ++ i ) {
std::cout << i << '\n';
}
}
int
main()
{
scribble();
testit();
return 0;
}
对 is 的调用std::operator<<( std::ostream&, char const* )
可能在这个特定的内存单元中留下了不同于 0 的东西。(或者编译器已经对其进行了优化。在关闭所有优化的情况下尝试此操作。)g++ 和 VC++ 都不初始化i
in testit
。
C 和 C++ 标准都非常清楚,只有一种内存被初始化,那就是用于静态存储的内存。
具有静态存储持续时间的变量保证为零(未初始化或具有构造函数)。其他一切都是“未初始化的”,这意味着“你不知道它会是什么”——其中一个选项当然是它为零。
至少在某些情况下,几乎可以保证所有其他变量都不为零——而且很可能您无法通过简单的测试程序找到这些情况。
例如,对于“原始”内存, malloc
(或new
)内存通常为零,但是用一些东西填充它,然后释放它并再次使用它,它不再是零。
堆栈上的变量几乎不可避免地会有不同的值,这取决于先前的调用是什么(因此,在代码访问的前一个函数中,哪些东西被放入了堆栈)。
它可能取决于编译器到编译器,但最好让初始化成为一种习惯,因为您可能不知道最终会使用哪个旧编译器,并且您可能会因为使用未初始化的垃圾值而搞砸......另一个编译器是http ://codepad.org/也对其进行初始化..
没有一个编译器用零初始化。我可以说不知何故你很幸运。在您提供的在线编译器中尝试此操作。
for(int i;i < 10; ++i)
{
int a;
cout << a << endl;
a = 1;
}
你会看到第一次 a 等于 0,接下来 9 次等于 1。