什么是聚合初始化?

36
第4章第231页的《Java编程思想(第2版)》中的“数组初始化”部分如下所述:
在C语言中,数组的初始化容易出错且繁琐。C++使用聚合初始化来使其更加安全。Java没有像C++那样的“聚合体”,因为在Java中一切都是对象。不过,Java有数组,并且支持数组初始化。
为什么在C语言中容易出错且繁琐呢?什么是聚合初始化,为什么它更安全?我在Bruce Eckel的《Thinking in C++(第2版)》中看到了“聚合初始化”这一章节,但它并没有让我信服。

19
也许这意味着作者在说服人们学习Java而非C方面有经济利益,因为他没有销售C语言的书。 - Ben Voigt
1
C语言提供了复合字面量形式的聚合初始化,不确定上述描述的含义。但我不认为它是“易错的”。 - Nobilis
2
作者认为C语言自C89以来没有什么变化。 - Yu Hao
1
@YuHao 我以为C89中也有数组初始化器,只是没有结构体的...至少,这个在我使用--std=c89编译时可以通过。 - millimoose
1
投票关闭,因为在不知道书的作者所说的“容易出错”和“更安全”的含义的情况下,这最多是在提问。 - millimoose
显示剩余2条评论
2个回答

34

首先回答主要问题,聚合初始化是使用括号括起来的初始化列表来初始化聚合类型(即数组或结构体[在C ++中,只有某些类型的结构体被视为聚合类型])的所有成员。

显然,

int ar[] = { 1 , 2 };

比...更安全。
int ar[2];
ar[0] = 1;
ar[1] = 2;

因为后者会给单个元素的索引初始化留下足够的打字错误和其他错误的机会。
看看今天的C和C++,我不清楚作者为什么区分C和C ++。这两种语言都可以对数组进行聚合初始化。
一种可能是作者参考了旧版本的C标准。值得注意的是,在ANSI C(C89)中,对于聚合初始化有一个重要限制:所有初始化程序都必须是常量表达式:
/* This is possible in C89: */
f(int i)
{ int ar[] = { 1 , 2 }; }

/* But this is not
   (because i is not a constant expression):
*/
f(int i)
{ int ar[] = { i , i+1 }; }

这是由于C89标准中3.5.7的规定(引用我在这里找到的草案): 所有具有静态存储期限的对象初始化程序中的表达式,或具有聚合或联合类型的对象的初始化器列表中的表达式都必须是常量表达式。
这明显限制了聚合初始化的实用性(即使在1989年,我认为许多编译器也实现了扩展以使聚合初始化对非常量表达式也有效)。
较晚版本的C标准没有这个限制,而我相信C ++的标准版本(从C ++ 98开始)也从未有过这样的限制。
我只能猜测,但也许这就是作者想表达的意思?

我认为他指的是 int ar[3] = {};,这在 C++ 中是有效的,但在 C 中不是。当然,int ar[3] = {0}; 在两种语言中都可以使用... 但将其更改为 struct S s[3] = {}; 可以感受到 C++ 的 "聚合初始化" 究竟是什么。 - Nemo

1
我假设作者在警告您C和C++不执行大小限制。在C和C++中,数组会衰变成为指向它们第一个元素的指针。然后使用指针算术方法通过索引来查找所引用的元素。由于数组不是对象,编译器不存储其大小,因此没有长度检查。在Java中,数组是对象,因此它们的大小是已知的。可以对此大小进行检查,以防止开发人员越界访问内存。
我发现'C++使用聚合初始化使其更安全'这种说法在这种情况下非常奇怪。
聚合初始化是大多数现代语言都采用的方式,其具体如下:
int intArray[3] = {1,2,3};
int int2DArray[2][2] = {{1,2}, {3,4}};

这种初始化方式假定您事先知道数组的大小和内容。这种初始化方式可以防止越界,并提供使用设定的值初始化数组的功能。也许在这种情况下,作者想到了一个声明了大小为5的静态C数组的开发人员。然后,该开发人员创建一个循环以初始化其内容,但超出了数组的边界,写入了不属于他/她的内存。

1
在C语言中,int intArray[3] = {1,2,3}; 也是允许的吧? - user13267
@Paul:int intArray[] = {1,2,3}; -- 看,大小由编译器计算,不存在越界问题。但是即使您指定了数组的大小,编译器也会检测是否有太多的初始化器。 - Ben Voigt
@Ben:谢谢你的示例。我应该也包括在内。 - Paul Renton
数组肯定是对象。 - Lightness Races in Orbit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接