在C语言中,如果像这样初始化数组:
int a[5] = {1,2};
然后,数组中所有未显式初始化的元素都将隐式初始化为零.
但是,如果我像这样初始化一个数组:
int a[5]={a[2]=1};
printf("%d %d %d %d %d\n", a[0], a[1],a[2], a[3], a[4]);
output:个
1 0 1 0 0
我不明白,为什么a[0]
打印的是1
而不是0
?这是未定义的行为吗?
这个问题是在一次采访中提出的.
在C语言中,如果像这样初始化数组:
int a[5] = {1,2};
然后,数组中所有未显式初始化的元素都将隐式初始化为零.
但是,如果我像这样初始化一个数组:
int a[5]={a[2]=1};
printf("%d %d %d %d %d\n", a[0], a[1],a[2], a[3], a[4]);
output:个
1 0 1 0 0
我不明白,为什么a[0]
打印的是1
而不是0
?这是未定义的行为吗?
这个问题是在一次采访中提出的.
戴利:我不认为int a[5]={a[2]=1};
的行为有很好的定义,至少在C99中是这样.
有趣的是,对我来说唯一有意义的部分是您询问的部分:a[0]
被设置为1
,因为赋值操作符返回赋值的值.其他一切都不清楚.
如果代码是int a[5] = { [2] = 1 }
,一切都会很简单:这是一个指定的初始值设定项,将a[2]
设置为1
,其他设置为0
.但对于{ a[2] = 1 }
,我们有一个包含赋值表达式的非指定初始值设定项,我们掉进了兔子洞.
以下是我迄今为止的发现:
a
必须是局部变量.
6.7.8 Initialization个
- 具有静态存储持续时间的对象的初始值设定项中的所有表达式应为常量表达式或字符串文字.
a[2] = 1
不是一个常量表达式,所以a
必须具有自动存储.
a
在其自身的初始化范围内.
6.2.1 Scopes of identifiers个
- struct 、联合和枚举标记的作用域在
声明符是a[5]
,因此变量在其自身初始化的范围内.
a
在它自己的初始化中是活动的.
6.2.4 Storage durations of objects
其标识符声明时没有链接且没有存储类的对象 说明符
static
有automatic storage duration.对于这样一个没有可变长度数组类型的对象,its lifetime extends from entry into the block with which it is associated until execution of that block ends英寸
a[2]=1
之后有一个序列点.
6.8 Statements and blocks
- full expression是一个不属于另一个表达式或声明符的表达式.
请注意,例如在int foo[] = { 1, 2, 3 }
中,{ 1, 2, 3 }
部分是一个括号内的初始值设定项列表,每个初始值设定项后面都有一个序列点.
初始化按初始值设定项列表顺序执行.
6.7.8 Initialization个
- 每个括号内的初始值设定项列表都有一个关联的current object.当没有
- 初始化应按初始值设定项列表顺序进行,每个初始值设定项提供一个
但是,初始值设定项表达式不一定按顺序计算.
6.7.8 Initialization个
- 初始化列表表达式中出现任何副作用的顺序为 未指明.
然而,仍有一些问题没有得到解答:
序列点是否相关?基本规则是:
6.5 Expressions个
- 在上一个序列点和下一个序列点之间,对象应有其存储值
a[2] = 1
是一个表达式,但初始化不是.
这与附件J略有矛盾:
J.2 Undefined behavior
- 在两个序列点之间,一个对象被多次修改,或者被修改
附件J表示,任何修改都是重要的,而不仅仅是表达式的修改.但鉴于附件是非规范性的,我们可能可以忽略这一点.
关于初始值设定项表达式,子对象初始化是如何排序的?是否先判断所有初始值设定项(以某种顺序),然后使用结果(以初始值设定项列表顺序)初始化子对象?或者它们可以交错?
我认为int a[5] = { a[2] = 1 }
的执行如下:
a
的块时,会分配a
的存储.内容目前还不确定.a[2] = 1
),后跟一个序列点.它在a[2]
中存储1
,然后返回1
.1
用于初始化a[0]
(第一个初始化器初始化第一个子对象).但是这里的情况变得模糊了,因为剩下的元素(a[1]
、a[2]
、a[3]
、a[4]
)应该初始化为0
,但不清楚什么时候:在计算a[2] = 1
之前会发生吗?如果是这样,a[2] = 1
将"赢"并覆盖a[2]
,但该赋值是否会有未定义的行为,因为零初始化和赋值表达式之间没有序列点?序列点是否相关(见上文)?还是在所有初始值设定项都被计算之后,零初始化就发生了?如果是这样,a[2]
应该是0
.
因为C标准没有明确定义这里发生了什么,我认为行为是未定义的(通过省略).