使用复合文字声明结构的初始值时,引用先前设置的字段的预期行为是什么:具体可以:
struct foo v = { .v1 = ..., .v2 = .v1+1 };
更完整的示例:
struct s {
int i1 ;
int i2 ;
} ;
void func(void)
{
// Case A:
struct s v1 = { 3 } ;
v1 = (struct s) ( .i1 = 4, .i2 = v1.i1+10 }
// always v1.i2=13, NOT 14
// Case B:
// Is this legal ?
struct s v2 = ( .i1 = 1, .i2 = v2.i1+10 }
// Under GCC, v2.i2 = 11
}
在情况 A - 标准很明确,根据赋值之前 v1 的值 (v1.i1=3) 创建“临时”复合文字,导致 v2.i2 = 13。解释是,这基本上是:
struct s v1 = { 3 } ;
struct s temp = ( .i1 = 4, .i2 = v1.i1+10 }
v1 = temp ;
对于情况 B,至少对于 GCC,看起来好像可以在 SAME 语句中引用先前设置的值 - 在这种情况下,i2 设置为 11,这意味着这不是使用临时变量实现的,这会在 v2 中产生结果.i2 = 10;
// NOT the same as struct v1 = { ... };
struct s temp = ( .i1 = 4, .i2 = v1.i1+10 }
struct s v1 = temp ;
我的问题:C99/C23 标准对第二种情况有何规定?编译器应该将其标记为警告/错误吗?
我用 GCC9(-Wall、-Wextra)以及 Coverity 尝试了上述操作 - 没有出现任何问题。
C 标准没有说明在评估任何初始化器之前初始化聚合的哪些元素或成员。
该标准包含有关元素或成员初始化顺序的措辞(在 C 2023 草案 N3096 6.7.10 中)。然而,这个顺序最多只能告诉我们值在元素或成员中存储的顺序。它没有说明这些值是何时准备的。 6.7.10 24 说:
初始化列表表达式的计算彼此之间的顺序不确定,因此任何副作用发生的顺序是未指定的。
该措辞首次出现于 C 2011 6.7.9 23(根据草案 N1570 确定)。 (在此之前它不存在的事实并不意味着存在排序;这意味着 C 标准对此保持沉默,因此没有断言有关排序的任何内容。)
因此,在
struct s v2 = ( .i1 = 1, .i2 = v2.i1+10 }
中,编译器可以自由地生成按以下顺序运行的程序:
1
。v2.i1+10
。i1
初始化为步骤 1 的结果。i2
初始化为步骤 2 的结果。按照此顺序,
v2.i1
在评估时未初始化。