为什么"++x || ++y && ++z"计算“”“x2B;”x“首先,即使运算符“&&”优先级高于“||”
为什么 ++x || ++y && ++z
先计算++x
,即使运算符&&
的优先级高于||
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
为什么 ++x || ++y && ++z
先计算++x
,即使运算符&&
的优先级高于||
?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(11)
啊?
如果您说
&&
比||
绑定更紧密 (这是正确的),则该表达式相当于since
||
短路,需要先评估左侧。如果您的意思是它应该等效于
同样仍然正确,因为
&&
也会短路,这意味着需要首先评估||
,这反过来又使++x
成为第一个要评估的东西。Huh?
If you're saying that
&&
binds tighter than||
(which is true), the expression is then equivalent toSince
||
short-circuits, it needs to evaluate the left-hand side first.If you mean that it ought to be equivalent to
The same is still true, since
&&
also short-circuits, meaning the||
needs to be evaluated first, which in turn makes++x
the first thing to evaluate.由于
&&
的优先级高于||
,这意味着您的表达式相当于:因此,在程序开始评估
& 的结果之前, &
,它必须评估++x
以确定是否应该评估||
的右侧操作数(逻辑二元运算符是“短” -电路”,这意味着如果左侧足以确定结果,则他们不会评估右侧)。这里没有什么可疑的或特定于编译器的内容。该表达式的行为由 C 标准精确指定,并且在任何编译器上都是相同的。如果x
、y
和z
都是同一个变量,它甚至会起作用,因为||
和 < code>& 引入序列点。Since
&&
has higher precedence than||
, it means your expression is equivalent to:Thus, before the program even begins evaluating the result of
&&
, it has to evaluate++x
to determine whether the right-hand operand of||
should even be evaluated (logical binary operators are "short-circuiting", meaning they do not evaluate the right-hand side if the left-hand side is sufficient to determine the result). There is nothing fishy or compiler-specific here. The behavior of this expression is specified exactly by the C standard and will be the same on any compiler. It would even work ifx
,y
, andz
were all the same variable, since||
and&&
introduce sequence points.放松,R 和其他人已经解释了到底发生了什么。所以我补充一下:
你的问题的前提是错误的。
&&
具有较高优先级这一事实并不意味着它周围的操作数必须在表达式中具有较低优先级的任何操作数之前进行计算。即使||
和&&
的特殊情况短路,情况也不一定如此。例如,考虑
a=b+c+d*e
;*
的优先级高于+
,但这并不意味着d*e
必须在b+c
之前计算代码>.它只是意味着在我们将乘积作为一个整体添加到表达式之前必须对其进行求值。编译器可以将此表达式计算为temp1=d*e
、temp2=b+c
、a=temp1+temp2
或者它可以计算 <代码>temp1=b+c、temp2=d*e
、a=temp1+temp2
。两者同样有效。由于
||
和&&
的短路行为,对计算顺序有一些额外的限制。附带说明:一般来说,我会避免编写这样的代码。我可以很容易地看到另一个试图阅读这段代码的程序员对增量何时会发生以及何时不会发生感到困惑。好吧,也许如果你使用真正的变量名,它看起来就不会那么奇怪了。
我偶尔会依靠短路来防止副作用。就像
我依靠短路来防止读取(如果我们已经在文件末尾),或者
我依靠第一个测试来短路 false,所以我不应该执行删除操作t。但这些例子对我来说似乎非常简单,我希望任何有能力的程序员都能看到我在做什么。但当这些例子变得晦涩难懂时,我认为需要对其进行解释。考虑
如果
lastDepositAmount()
有副作用,那么如果customerType
是零售,则这种副作用永远不会发生。我认为这对读者来说不一定是显而易见的。 (部分是因为函数名称暗示它正在检索数据而不执行任何更新,部分是因为客户类型和存款金额之间没有明显的关系——这听起来像是两个独立的事情。)不可否认,这是主观。但当有疑问时,请选择简单和清晰,而不是微不足道的性能改进。始终选择简单性和清晰性,而不是“嘿,这是对晦涩功能的一种很酷的使用方式,任何读到这篇文章的人都会对我必须多么聪明才能很好地理解语言才能做到这一点印象深刻”。Unwind, R and others have explained what really happens. So let me just add:
The premise of your question is faulty. The fact that the
&&
has higher precedence doesn't mean that operands that surround it must be evaluated before any operands in the expression with lower precedence. Even where the special case short-circuiting of||
and&&
this wouldn't necessarily be so.For example, consider
a=b+c+d*e
;*
has higher precedence than+
, but that doesn't mean thatd*e
must be evaluated beforeb+c
. It just means that it must be evaluated before we add the product to the expression as a whole. A compiler could evaluate this expression astemp1=d*e
,temp2=b+c
,a=temp1+temp2
or it could evaluatetemp1=b+c
,temp2=d*e
,a=temp1+temp2
. Both would be equally valid.With the short-circuiting behavior of
||
and&&
, there are some additional restrictions placed on order of evaluation.As a side note: In general I would avoid writing code like this. I can easily see another programmer trying to read this code getting confused about just when the increments will happen and when they won't. Well, maybe if you used real variable names it would not look so bizarre.
I do occasionally rely on short-circuiting preventing side effects. Like
I'm relying on the short-circuit to prevent reading if we're already at end of file, Or
I'm relying on the first test to short-circuit on false so I don't do the delete when I shouldn't. But these examples seem pretty straightforward to me, I'd hope any competent programmer would see what I'm doing. But when the examples get cryptic, I think it needs to be broken out. Consider
If
lastDepositAmount()
had a side effect, then ifcustomerType
is retail this side effect will never happen. I don't think that would necessarily be obvious to a reader. (Partly because the function name implies that it is retrieving data and not performing any update, and partly because there is no obvious relationship between the customer type and the amount of a deposit -- these sound like two independent things.) Admittedly, this is subjective. But when in doubt, choose simplicity and clarity over a trivial performance improvement. Always choose simplicity and clarity over "hey this is a way cool use of an obscure feature, anyone reading this will be impressed at how smart I must be to understand the language well enough to do this".这里有非常错误的答案。
此表达式的求值顺序与实现无关。这是明确定义的!
由于
&&
绑定高于||
,因此该表达式等效于++x || (++y && ++z)
。此外,&&
和||
都是短路的,因此如果表达式的左侧足以确定值,右侧从不评估。什么时候有这样的情况呢?好吧,我们知道
False &&无论
始终解析为a
的值是什么,aFalse
,特别是即使a
不是单个值而是一个复杂的表达。因此我们根本不评估a
。同样,True || a
始终解析为True
。在此示例中,这导致了非常明确的求值顺序:首先
++x
,然后(如果有的话)++ y
和然后(再次强调:如果有的话)++z
。There are horribly wrong answers here.
The order of evaluation of this expression is not implementation dependent. It is well-defined!
Since
&&
binds higher than||
, this expression is equivalent to++x || (++y && ++z)
. Furthermore, both&&
and||
are short-circuited, so if the left-hand side of the expression suffices to determine the value, the right-hand side is never evaluated.When is this the case? Well, we know that
False && a
always resolves toFalse
, no matter the value ofa
, in particular even ifa
is not a single value but instead a complex expression. Therefore we don’t evaluatea
at all. Likewise,True || a
always resolves toTrue
.This results in a very definite order of evaluation in this example: first
++x
, then (if at all)++y
and then (again: if at all)++z
.如图所示,使用波兰树数据结构对运算符进行评估,这是一种深度优先的评估算法。
让我们为操作命名:
A = ++x
B = ++y
C=++z
D=B&& C
E = C || D
评价顺序:A、B、C、D、E。
当然,C 有一个优化,如果 A 为 true,那么 E 将被评估为 true,而不评估 BC 和 D。同样,如果 B 为 false,则不会评估 C,以优化评估速度。
The operators are evaluated using the Polish tree datastructure, as in the diagram, and it's a depth-first evaluation algorithm.
Let's give names to the operations:
A = ++x
B = ++y
C = ++z
D = B && C
E = C || D
Evaluation order: A, B, C, D, E.
Of course, C has an optimisation and if A is true, then E will be evaluated as true without evaluating B C and D. Similarly, if B is false, then C won't be evaluated to optimize the evaluation speed.
++ 具有最高优先级,因为它的 pre 增量。这意味着该操作的结果值被传递给二元运算符。然而有趣的是 ++x 与其余部分的短路。如果 ++x 为真,那么剩下的可能根本就不会完成。
++ has highest priority of all, as its pre increment. This means that the value of the result of this operation is passed to binary operators. However the interesting thing is the short circuit of ++x or'ed with the rest. If ++x is true then the rest may not be done at all.
优先级和求值顺序不是一回事,尤其是在这种情况下。所有优先级告诉您表达式应该被解析为
IOW,这意味着进行 OR 运算的表达式是
++x
和(++y && ++z )
。它不意味着(++y && ++z)
将在++x之前评估代码>.
对于逻辑运算符
||
和&&
,计算始终从左到右(在线 C 标准,第 6.5.13 和 6.5.14 节)。对于任何表达式a
都将被完全求值;除非a
的结果为 0,否则b
不会被计算(想想a
代表++x
和b
代表++y && ++z
)。类似地,对于任何表达式a
都将被完全求值;除非a
的结果不为 0,否则b
不会被求值。因此,对于您的情况,首先对表达式
++x
求值。如果结果为 0,只有才会++y && ++z
被评估。||
和&&
的特殊之处在于,保证计算顺序是从左到右。对于按位运算符或算术运算符来说,情况并非如此。例如,在表达式中,表达式
++x
、++y
和++z
可以按任意顺序求值;所有优先级告诉您的是(y+1) * (z+1)
的结果将添加到x+1
的结果中。Precedence and order of evaluation are not the same thing, especially in this case. All precedence tells you is that the expression should be parsed as
IOW, it means that the expressions being OR'd together are
++x
and(++y && ++z)
. It does not mean that(++y && ++z)
will be evaluated before++x
.For the logical operators
||
and&&
, evaluation is always left-to-right (Online C Standard, Sections 6.5.13 and 6.5.14). For any expressiona
will be completely evaluated;b
will not be evaluated unless the result ofa
is 0 (think ofa
standing in for++x
andb
standing in for++y && ++z
). Similarly, for any expressiona
will be completely evaluated;b
will not be evaluated unless the result ofa
is not 0.So for your case, the expression
++x
is evaluated first. If the result is 0, only then will++y && ++z
be evaluated.||
and&&
are special in that the order of evaluation is guaranteed to be left-to-right. That is not true of the bitwise or arithmetic operators. For example, in the expressionthe expressions
++x
,++y
, and++z
may be evaluated in any order; all precedence tells you is that the result of(y+1) * (z+1)
will be added to the result ofx+1
.前两个答案很好地解释了这一点......我想指出 ||是“否则”。
如果左侧为真,则右侧不会被触及。 && 的左侧如果右侧为 false,则 (AndAlso) 不会被触及。
如果您希望两边都增加,请使用 |和&。
http://msdn.microsoft.com/en -us/library/2h9cz2eb(v=VS.80).aspx
MSDN 有一些表格显示部件是如何“(未评估)”的。
如果第 1 部分已经确定性地预先确定了结果,为什么还要触及第 2 部分呢?
Top two answers explain it rather well... I'd point out that || is "OrElse".
Right side doesn't get touched if left side is true. Left side of && (AndAlso) doesn't get touched if right side is false.
If you want both sides to get incremented, use | and &.
http://msdn.microsoft.com/en-us/library/2h9cz2eb(v=VS.80).aspx
MSDN has tables that show how parts are "(not evaluated)".
Why touch part 2, if Part 1 pre-determines the outcome deterministically?
我已经很久没有使用 C 语言了,但如果我没记错的话,++ 是一个一元运算符,它总是优先于二元运算符。如果你仔细想想,这是有道理的。
It has been a long time since I have worked with C, but if I remember correctly, ++ is a unary operator which always has precedent over binary operators. Makes sense if you think about it.
如果您的操作对顺序敏感,则不应依赖感知的运算符优先级,因为不同的编译器(以及同一编译器的不同版本)可能会以不同的方式实现优先级。
不管怎样,b 定义 ++x 意味着 x 必须在使用之前递增,因此您希望它在执行中获得高优先级。
You shouldn't rely on perceived operator priority if your operations are order sensitive, as different compilers (and differing versions of the same one) could implement priorities differently.
Eitherway b definition ++x means that x must be incremented BEFORE it is used and so you would expect it to be given high prioroty in execution.
不不不
是在同行投诉后编辑:)
是的!
No no no
YesEdit after peer complaints :)
YES!