【发布时间】:2011-01-26 02:28:37
【问题描述】:
这是一个愚蠢的问题。 :)
[编辑:愚蠢与否,结果证明这是一个 C++ 特殊性问题,请参阅 UPDATE_2]
假设我们有:
int a = 0; // line 1
int b = ++a; // line 2
第 2 行发生的事情是(注意,数字只是标记,并没有指定确切的顺序):
= [1: write result of (3) to result of (2)]
/\
[2: take "b" l-value] [3: convert result of (4) to an r-value ]
|
[4: take "a" l-value, "increment" and return it]
(4)中的“写”在(3)中的“读”之前“排序”,并且由于之间没有序列点,因此不能保证副作用发生在(3)之前(有在 (4) 本身内部也是一个“读取”,但在 “写入”之前排序,因此不会产生 UB)。
那么,上面的错误在哪里?
[更新,针对没有经验的序列点律师 :)]
换句话说,问题是:
无论是左值到右值的转换(“读取”)还是递增(“写入”)副作用,似乎都存在“竞争”。
在 C 中,将给出一个 UB,根据 JTC1/SC22/WG14 N926 "Sequence Point Analysis"*(参见示例 5:
int x,y; (x=y) + x; // UB)。请注意,这不是应该使用后增量的情况,因为 (3) 和 (4) 将构成单个 [(3):取“a”左值,转换它到 r 值并返回该 r 值] “写入”副作用延迟到下一个序列点之前的某个地方
_
(*) 这看起来像是 C99 标准委员会成员给出的主题最清晰的系统性原理。
[UPDATE_2]
经验教训:永远不要根据 C 规则来判断 C++ :))。我确实想知道为什么 N926(它清楚地描述了 C99 的方式)在产生 l 值的前增量的主题上“不够清楚”。
1234563并且晦涩难懂。
[UPDATE_3]
"The undefinedness of a common expression." 讨论了一些相关主题(至少在 ~ 较新的一半),此外,委员会人员 here 讨论了此事(参见“222. 序列点和左值-返回运算符”)。
【问题讨论】:
-
嗯,很有趣。这个问题只发生在 C++ 中,而不是 C 中(C 中的 ++a 不是左值)。
-
感谢您的更新,这使问题变得更加有趣。显然我也不够老练,无法从您的
C标签中猜出您只是在考虑 C++ 之后。 -
@John 那是 我的 错(以及导致问题本身的不一致,请参阅 update_2)。
-
顺便说一句,我真的很喜欢你链接的论文。我只是在读它,它很有趣:)
标签: c++ c standards language-lawyer