排序点和评估顺序

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机器学习问题与解答系列 | 二十一:分类排序回归模型的评估

搜索排序评估方法:作为产品,这个你必须要了解

参数评估后是不是对参数绑定进行排序?

ACL 排序和评估。啥应该优先 帐户或组、aco 或父 aco

线上直播排序评估神器---交叉试验方法之介绍

83. 删除排序链表中的重复元素