排序点和评估顺序
Posted
技术标签:
【中文标题】排序点和评估顺序【英文标题】:Sequence points and order of evaluation 【发布时间】:2012-02-22 01:30:18 【问题描述】:我正在阅读 K&R,并且在评估 a[i]=i++
之类的表达式时遇到了这个关于行为不确定性的示例;
6.5.2 美元的 C99 规范表明
在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的评估修改一次。此外,应仅读取先验值以确定要存储的值。
上面来自 K&R 的示例在第一条陈述中成立。请解释它是如何在第二次失败的。
在涉及序列点的情况下,标准是否说明了子表达式的评估顺序。例如。 a[i++] || b[i++]
。我知道这些是从左到右评估的,但是如何从上述陈述中得出,或者它是否在标准中的某处明确说明?
【问题讨论】:
Any good reason why assignment operator isn't a sequence point? 的可能重复项 Undefined Behavior and Sequence Points的可能重复 @undur_gongor 据我所知,在序列点和评估顺序方面,C 和 C++ 没有区别。 @Lundin 感谢您提供的精彩链接。 @Lundin:那么,这可能是一个很好的答案的一部分。不过,这个问题不是重复的。 【参考方案1】:在序列点的情况下,标准是否说明了子表达式的评估顺序?
在条件运算符&&
和||
的情况下,评估顺序是明确定义的,这就是短路起作用的原因。
c99 标准明确规定。
参考: c99 标准
附件 J:J.1 未指明的行为
1 以下未指定: .....
计算子表达式的顺序和副作用的顺序 发生,除非为函数调用 ()、&&、||、?: 和逗号指定 运营商 (6.5)。 .....
进一步介绍,6.5.14 逻辑或运算符
4) 不同于按位 |运算符,||运算符保证从左到右的评估;在计算第一个操作数之后有一个序列点。如果第一个操作数比较不等于 0,则不计算第二个操作数。
以及逻辑与:
6.5.13 逻辑与运算符
与按位二进制 & 运算符不同,&& 运算符保证从左到右的求值; 如果对第二个操作数求值,则在求值之间存在一个序列点 第一个和第二个操作数。如果第一个操作数比较等于 0,则第二个 不计算操作数。
【讨论】:
谢谢,但你能解释一下我问的关于 a[i]=i++; 的第一个问题吗? @Parminder 赋值运算符在 C 中不是序列点。注意:C++11 引入了序列前/后的概念,a[i]=i++ 为well defined in C++11。另见***.com/questions/4362501/… 真棒答案!这有助于我了解a || b++ && c
是否总是对b++
进行评估。它没有,但是 && 运算符的更高优先级会引起很多人的争论。【参考方案2】:
对于问题的第一部分:
这句话适用于被表达式改变的对象,即i
(和a[i]
)。因此,i
的先前值应专门用于确定i
的“新”值。
但表达式也“使用”它来确定要写入的数组元素。
背景是,否则将不清楚i
是否表示i
在增量之前或之后的值。
【讨论】:
谢谢,但我对此有另一个疑问。乍一看,++i==i
这样的表达式似乎是模棱两可的。但它并没有试图“改变”任何东西,除了 i。那么这也是未定义的行为吗??
我不想改变任何左值。我想说的是,在从右到左评估时,我只更改了一次i
,当我第二次访问i
时,我这样做是为了更改i
本身的值。这证实了我猜的第二个陈述。所以有什么问题 ?这是具有明确行为的合法表达式吗?
没有重新赋值,只有增量操作。这是==
不是=
,以防你错过。
对不起,我一定是瞎了。但是,您正在使用对象i
的值被更改,不仅用于计算i
的新值,还用于比较。因此,您违反了与您的问题相同的约束。
我想我现在明白了。表达式未定义,因为Any access to an object that is being modified between two sequence points should be to change that object only and nothing else.
在此示例中,我们使用它进行比较,这违反了第二个“规则”。但它仍然适用于第一个陈述。干杯!!以上是关于排序点和评估顺序的主要内容,如果未能解决你的问题,请参考以下文章
Hulu机器学习问题与解答系列 | 二十一:分类排序回归模型的评估