序列点和运算符优先级有什么区别? [英] What is the difference between a sequence point and operator precedence?

查看:101
本文介绍了序列点和运算符优先级有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑经典序列点示例:

i = i++;

C和C ++标准规定,上面的表达式的行为未定义,因为=运算符未与序列点关联.

The C and C++ standards state that the behavior of the above expression is undefined because the = operator is not associated with a sequence point.

让我感到困惑的是,++的优先级高于=,因此,基于优先级的上述表达式必须先求值i++,然后再进行赋值.因此,如果我们以i = 0开头,则应始终以i = 0(如果表达式为i = ++i,则为i = 1)结束,而不是未定义的行为.我想念什么?

What confuses me is that ++ has a higher precedence than = and so, the above expression, based on precedence, must evaluate i++ first and then do the assignment. Thus, if we start with i = 0, we should always end up with i = 0 (or i = 1, if the expression was i = ++i) and not undefined behavior. What am I missing?

推荐答案

运算符优先级(和关联性)说明了表达式的解析和执行顺序.但是,这与操作数的求值顺序无关,这是一个不同的术语.示例:

Operator precedence (and associativity) state the order in which an expression is parsed and executed. However, this says nothing about the order of evaluation of the operands, which is a different term. Example:

a() + b() * c()

运算符的优先级指示b()的结果和c()的结果必须先相乘,然后再与a()的结果相加.

Operator precedence dictates that the result of b() and the result of c() must be multiplied before added together with the result of a().

但是,它没有说明这些功能的执行顺序.每个运算符的评估顺序对此进行了指定.多数情况下,评估的顺序是不确定的(行为未指定),这意味着标准允许编译器按照自己喜欢的顺序进行操作.编译器不需要记录此命令,也不需要表现一致.这样做的原因是为编译器提供了更多的表达式解析自由,这意味着编译速度更快,代码也可能更快.

However, it says nothing about the order in which these functions should be executed. The order of evaluation of each operator specifies this. Most often, the order of evaluation is unspecified (unspecified behavior), meaning that the standard lets the compiler do it in any order it likes. The compiler need not document this order nor does it need to behave consistently. The reason for this is to give compilers more freedom in expression parsing, meaning faster compilation and possibly also faster code.

在上面的示例中,我编写了一个简单的测试程序,并且编译器按a()b()c()的顺序执行了上述功能.程序需要先执行b()c()才能将结果相乘,这一事实并不意味着它必须以任何给定的顺序求值那些操作数.

In the above example, I wrote a simple test program and my compiler executed the above functions in the order a(), b(), c(). The fact that the program needs to execute both b() and c() before it can multiply the results, doesn't mean that it must evaluate those operands in any given order.

这是进入顺序点的地方.它是程序中必须完成所有先前评估(和操作)的给定点.因此,顺序点主要与求值顺序有关,而与运算符的优先级无关.

This is where sequence points come in. It is a given point in the program where all previous evaluations (and operations) must be done. So sequence points are mostly related to order of evaluation and not so much operator precedence.

在上面的示例中,三个操作数彼此之间是未排序的,这意味着没有序列点可以指示求值顺序.

In the example above, the three operands are unsequenced in relation to each other, meaning that no sequence point dictates the order of evaluation.

因此,当在此类无序列表述中引入副作用时,就会出现问题.如果我们写i++ + i++ * i++,那么我们仍然不知道这些操作数的求值顺序,因此我们无法确定结果将是什么.这是因为+*都具有未指定/未排序的求值顺序.

Therefore it turns problematic when side effects are introduced in such unsequenced expressions. If we write i++ + i++ * i++, then we still don't know the order in which these operands are evaluated, so we can't determine what the result will be. This is because both + and * have unspecified/unsequenced order of evaluation.

如果我们编写了i++ || i++ && i++,则行为将得到明确定义,因为&&||将评估顺序从左到右指定,并且在评估之间存在一个序列点左右操作数.因此,if(i++ || i++ && i++)是完美的可移植且安全(尽管不可读)的代码.

Had we written i++ || i++ && i++, then the behavior would be well-defined, because the && and || specifies the order of evaluation to be left-to-right and there is a sequence point between the evaluation of the left and the right operand. Thus if(i++ || i++ && i++) is perfectly portable and safe (although unreadable) code.

至于表达式i = i++;,这里的问题是=被定义为(6.5.16):

As for the expression i = i++;, the problem here is that the = is defined as (6.5.16):

在左和右操作数的值计算之后,对更新左操作数的存储值的副作用进行排序.操作数的求值没有顺序.

The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands. The evaluations of the operands are unsequenced.

该表达式实际上接近定义良好的位置,因为文本实际上说在计算右操作数之前不应更新左操作数.问题是最后一句话:操作数的评估顺序未指定/未排序.

This expression is actually close to be well-defined, because the text actually says that the left operand should not be updated before the right operand is computed. The problem is the very last sentence: the order of evaluation of the operands is unspecified/unsequenced.

由于表达式包含i++的副作用,因此它会调用未定义的行为,因为我们不知道操作数i还是操作数i++是首先求值的.

And since the expression contains the side effect of i++, it invokes undefined behavior, since we can't know if the operand i or the operand i++ is evaluated first.

(还有更多的东西,因为该标准还规定,操作数不应出于无关目的在表达式中使用两次,但这又是另一回事了.)

(There's more to it, since the standard also says that an operand should not be used twice in an expression for unrelated purposes, but that's another story.)

这篇关于序列点和运算符优先级有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆