5.5 初始值设定

我们已经看到(2.3节)初始值设定是对象定义的一个重要组成部分。初始值设定帮助我们确保程序执行始终处于定义的状态:我们无论何时访问一个对象,它都有一个众所周知的值来决定抽象机的状态。

要点5.35 所有的变量都应该初始化。

这条规则只有几个例外:可变长数组(VLA),参见6.1.3节,它不允许初始值设定,另外是必须高度优化的代码。后者主要发生在使用指针的情况下,因此这与我们还不相关。对于目前我们可以编写的大多数代码,现代编译器将能够跟踪一个值的源头,直到它最后一次赋值或初始化。多余的初始化或赋值将被优化掉。

对于诸如整型和浮点之类的标量类型,初始值设定只包含可以转换为该类型的表达式。我们见过很多这样的例子。另外一种选择,这样的初始值设定表达式可以用{}包围。下面是一些例子:

069-01

其他类型的初始值设定必须有这些{}。例如,数组的初始值设定包含对不同元素的初始化,每个初始值后面跟一个逗号:

069-02

正如我们所看到的,由于没有长度规范,所以具有不完整类型C的数组通过初始化指定长度来完成。这里,A只有一个元素,而C有四个。对于前两个初始值设定,应用了标量初始化的元素是从列表中标量的位置推断出来的:例如,B[1]初始化为7。像C这样的指定的初始值设定要好得多,因为相对声明中的一些小改变,它们可以使代码更加健壮。

要点5.36 为所有聚合数据类型使用指定的初始值设定。

如果你不知道如何初始化一个类型为T的变量,那么几乎[1]总是可以使用默认的初始值设定C T a ={0}来做。

要点5.37 对于所有不是VLA的对象类型,{0}是合法的初始值。

有几件事可以确保这一点。第一,如果我们省略指定(struct.membername,参见6.3节;或数组的[n],参见6.1节),初始化只是按照声明顺序C完成的:也就是说,默认初始值设定中的0指定了声明的第一个成员,然后所有其他成员也默认初始化为0。那么,标量的{}形式的初始值设定确保{0}也是合法的。

也许你的编译器会有这方面的警告。令人恼火的是,一些编译器的实现者不知道这个特殊的规则。它被明确地设计为C标准中的一个全面初始化值设定,因此这是我会关闭编译器警告的罕见情况之一。

在初始值设定中,我们通常必须为程序指定具有特定意义的值。


[1]例外情况是可变长度数组,参见6.1.3节。