一个(C/C++)数组初始化可以引用自身吗?

33

我想知道以下形式的初始化:

int  array[] = {
v - 1,
array[0] + 1
} ;
在第二个元素的初始化中,使用了第一个元素的值,但整个数组尚未初始化。这在使用g++编译时可以编译通过,但我不确定这是否是可移植和明确定义的构造方式?

23
因为并非所有编译器都符合标准 - 尤其是在像这样奇怪的边缘情况下。 - Björn Pollex
20
在C和C++中,“尝试一下”通常存在问题。许多编译器具有不兼容和非标准扩展,而且很多未定义的行为在单个平台上的少数测试中可能看起来是一致的。 - user395760
2
@DavidHeffernan 但也许他想要C和C++的答案,如果它们的行为不同? - Christian Rau
@DavidHeffernan 好的,我明白了。既然他没有明确表示他想要C和C++的答案,那么可能意味着他想要一个C/C++的答案,在这种情况下清理标签是个好主意。 - Christian Rau
1
@ChristianRau 没有所谓的 C/C++!! - David Heffernan
显示剩余8条评论
4个回答

18

见 3.3.2 声明点:

名称的声明点在其完整声明符(Clause 8)之后、初始化程序(如果有的话)之前立即出现,除非下面有特别说明。[ 示例:

int x = 12;
{ int x = x; }

这里第二个x使用它自己的(不确定)值进行初始化。- 示例结束]

所以你正确地引用了数组,它的名称在=之后是已知的。

然后,根据8.5.1聚合:

聚合是数组或类[...]

17:初始化器中的完整表达式按照它们出现的顺序进行评估。

然而,我没有看到任何关于何时将评估的值实际写入数组的参考资料,因此我不会依赖于此,并且甚至会进一步声明你的代码未定义。


13

据我所见,这个问题尚未有明确定义。标准(C++11, 8.5.1/17)规定,“初始化列表中的完整表达式按照它们出现的顺序进行评估”,但我并没有看到任何要求每个聚合元素在下一个被评估之前必须从其初始化列表的结果中初始化。


1
我认为这个问题由http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1343解决。最初我的报告只涉及命名空间作用域对象的非类初始化(参见When exactly is an initializer temporary destroyed?),但如果聚合元素是非类,则该问题同样存在。并且正如附加的最近说明所解释的那样,即使它是一个类对象,整个聚合初始化也似乎存在,因为此时没有构造函数调用会扩大初始化程序的完整表达式。

如果您使用了一个类而不是int,并且初始化将是一个构造函数调用,那么这个构造函数调用将成为包含聚合初始化程序元素的同一完整表达式的一部分,因此这里的顺序将是正确的,您的代码将被定义良好。


1
一个(C / C ++)数组初始化能引用自身吗?
这也是有效的C代码。
C语言有一些对应的段落(我强调)。
(C99,6.2.1p7)“结构、联合和枚举标记的作用域始于在声明标记的类型说明符中出现标记后。每个枚举常量的作用域始于其定义的枚举器在枚举器列表中出现后。任何其他标识符的作用域始于其声明符完成后。”

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