为什么是
的值int array[10];
在函数中声明时未定义,并且在声明为0
时被static
初始化吗?
我一直在阅读this question的答案,很明显
[函数中的表达式
int array[10];
]的意思是:无需进行任何初始化即可获取10 int大小的内存区域的所有权。如果将数组声明为全局1或函数中的静态,则所有尚未初始化的元素都将初始化为零。
问题:为什么这种行为?编译器程序员是否会决定(出于特定原因)?使用的特定编译器可以做些不同的事情吗?
为什么要问这个问题:之所以问这个问题,是因为我想使我的代码在体系结构/编译器之间可移植。为了确保它,我知道我总是可以初始化声明的数组。但是,这意味着我只会为此操作浪费宝贵的时间。那么,哪个是正确的决定?
答案 0 :(得分:6)
自动int array[10];
不会隐式归零,因为归零需要时间,您可能不需要将其归零。此外,您不仅要付出一次代价,而且每次控件超出初始化变量时都要付出代价。
静态/全局int array[10];
隐式归零,因为静态/全局变量是在加载时分配的。内存将从OS刷新,并且如果OS完全具有安全意识,则内存将已经为零。否则,加载代码(操作系统或动态链接器)将必须将它们归零(因为C标准要求这样做),但是对于所有全局变量/静态变量,它应该能够在一次调用memset
的情况下做到这一点。与一次将每个静态/全局变量清零相比,效率要高得多。
此初始化完成一次。即使函数内部的static
仅被初始化一次,即使它们具有非零的初始值设定项(例如static int x = 42;
。这也是为什么C要求static的初始值设定项为常量表达式的原因。)
由于所有全局变量/静态变量的加载时间清零是OS保证的或可以有效实施的,因此它也可能是标准保证的,从而使程序员的生活更轻松。
答案 1 :(得分:4)
这些值不是不确定的而是不确定的,并且它的行为是这样的,因为标准如此规定。
C standard的第6.7.9p10节关于初始化状态:
如果具有自动存储持续时间的对象不是 显式初始化,其值不确定。如果 具有静态或线程存储持续时间的对象不是 显式初始化,然后:
- 如果具有指针类型,则将其初始化为空指针;
- 如果具有算术类型,则将其初始化为(正数或无符号)零;
- 如果是聚合,则根据这些规则(递归)初始化每个成员,并将任何填充初始化为零位;
- 如果是联合,则根据这些规则初始化(递归)第一个命名成员,并初始化任何填充 到零位;
因此,对于在文件作用域或static
定义的任何变量,您都可以放心地假定值是零初始化的。对于在函数或范围内声明的变量,您不能对未初始化的变量做任何假设。
为什么,全局/静态变量是在程序启动时甚至在编译时初始化的,而局部变量每次在进入作用域时都必须初始化,这会花费时间。
答案 2 :(得分:3)
未在堆栈分配/局部变量中定义变量初始值的原因是效率。 C标准要求您的程序分配您的数组,然后填充它:
int array[10];
for (i = 0; i < 10; ++i)
array[i] = i * 42;
在这种情况下,任何初始化都是没有意义的,因此C标准希望避免这种情况。
如果您的程序需要将这些值初始化为零,则可以明确地做到这一点:
int array[10] = {0}; // initialize to zero so the accumulation below works
while (condition)
{
... // some code
for (i = 0; i < 10; ++i)
array[i] += other_array[i];
}
由您决定是否初始化,因为您应该知道程序的行为。对于不同的阵列,此决定将有所不同。
但是,此决定将不依赖于编译器-它们都符合标准。关于可移植性的一点细节-如果您不初始化数组,而在使用特定的编译器时仍看到其中的全零-请勿上当。值仍未定义;您不能依靠它们为0。
其他一些语言认为,零初始化即使是多余的也足够便宜,并且其优点(安全性)大于缺点(性能)。在C语言中,性能更为重要,因此另行决定。
答案 3 :(得分:1)
C的哲学是:a)始终信任程序员,并且b)在执行速度上优先于程序员便利。 C假定程序员处于最佳位置,以了解是否需要将数组(或任何其他auto
变量) 初始化为特定值,如果是,则足够聪明来编写代码自行完成。否则,不会浪费CPU周期。
对于数组访问的边界检查,对NULL
对指针解除引用的检查,等等。
这同时是C语言的最大优势(占地面积小的快速代码)和最大的弱点(使代码安全可靠的体力劳动)。