简体   繁体   English

为什么“++ x || ++ y && ++ z“计算”++ x“首先,即使运算符”&&“的优先级高于”||“

[英]Why does “++x || ++y && ++z” calculate “++x” first, even though operator “&&” has higher precedence than “||”

Why does ++x || ++y && ++z 为什么++x || ++y && ++z ++x || ++y && ++z calculate ++x first, even though the precedence of operator && is higher than || ++x || ++y && ++z首先计算++x ,即使运算符&&的优先级高于|| ?

Huh? 咦?

If you're saying that && binds tighter than || 如果你说&&绑定比||更紧密 ( which is true ), the expression is then equivalent to 这是真的 ),表达式相当于

++x || (++y && ++z)

Since || || short-circuits , it needs to evaluate the left-hand side first. 短路时 ,需要首先评估左侧。

If you mean that it ought to be equivalent to 如果你的意思是它应该相当于

(++x || ++y) && ++z

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成为第一个评估的东西。

Since && has higher precedence than || 因为&&优先级高于|| , it means your expression is equivalent to: ,这意味着你的表达相当于:

++x || (++y && ++z)

Thus, before the program even begins evaluating the result of && , it has to evaluate ++x to determine whether the right-hand operand of || 因此,在程序甚至开始评估&&的结果之前,它必须评估++x以确定是否是||的右手操作数。 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. 此表达式的行为完全由C标准指定,并且在任何编译器上都是相同的。 It would even work if x , y , and z were all the same variable, since || 如果xyz都是相同的变量,它甚至会起作用,因为|| and && introduce sequence points. &&引入序列点。

Unwind , R and others have explained what really happens. 放松R和其他人解释了真正发生的事情。 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 ; 例如,考虑a=b+c+d*e ; * has higher precedence than + , but that doesn't mean that d*e must be evaluated before b+c . *具有比+更高的优先级,但这并不意味着必须在b+c之前评估d*e 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 as temp1=d*e , temp2=b+c , a=temp1+temp2 or it could evaluate temp1=b+c , temp2=d*e , a=temp1+temp2 . 编译器可以将此表达式计算为temp1=d*etemp2=b+ca=temp1+temp2或者它可以评估temp1=b+ctemp2=d*ea=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 喜欢

if (!eof() && readNextInt()>0) 

I'm relying on the short-circuit to prevent reading if we're already at end of file, Or 如果我们已经在文件末尾,我依靠短路来防止阅读,或者

if (confirmDelete==YES && deleteEntry()!=-1) 

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 (customerType==RETAIL || lastDepositAmount()>100.00)

If lastDepositAmount() had a side effect, then if customerType is retail this side effect will never happen. 如果lastDepositAmount()有副作用,那么如果customerType是零售,那么这种副作用将永远不会发生。 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" . 总是选择简单和清晰, “嘿,这是一个很酷的使用一个不起眼的功能,任何读这篇文章的人都会对如何聪明地理解语言这一点感到印象深刻”

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) ,这个表达式相当于++x || (++y && ++z) ++x || (++y && ++z) . ++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 to False , no matter the value of a , in particular even if a is not a single value but instead a complex expression. 好吧,我们知道False && a总是解析为False ,无论a的值是a ,特别是即使a不是单个值而是复杂表达式。 Therefore we don't evaluate a at all. 因此,我们不评价a都没有。 Likewise, True || a 同样, True || a True || a always resolves to True . True || a总是解析为True

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 . 这导致在这个例子中非常明确的评估顺序: 首先是 ++x然后是 (如果有的话) ++y 然后 (再次:如果有的话) ++z

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 && CE = C || 让我们给出操作的名称:A = ++ x B = ++ y C = ++ z D = B && CE = 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 BC and D. Similarly, if B is false, then C won't be evaluated to optimize the evaluation speed. D评估顺序:A,B,C,D,E。当然,C有一个优化,如果A为真,那么E将被评估为真而不评估BC和D.同样,如果B为假,则C赢了不进行评估以优化评估速度。

替代文字

++ 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. 然而有趣的是++ x的短路或其他的短路。 If ++x is true then the rest may not be done at all. 如果++ x为真,则其余部分可能根本不会完成。

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 所有优先级都告诉您表达式应该被解析为

++x || (++y && ++z)

IOW, it means that the expressions being OR'd together are ++x and (++y && ++z) . IOW,这意味着OR一起的表达式是++x(++y && ++z) It does not mean that (++y && ++z) will be evaluated before ++x . 并不意味着(++y && ++z)之前将被评估 ++x

For the logical operators || 对于逻辑运算符|| and && , evaluation is always left-to-right ( Online C Standard , Sections 6.5.13 and 6.5.14). && ,评估总是从左到右( 在线C标准 ,第6.5.13和6.5.14节)。 For any expression 对于任何表达

a || b

a will be completely evaluated; a将被完全评估; b will not be evaluated unless the result of a is 0 (think of a standing in for ++x and b standing in for ++y && ++z ). b将不会被评价除非的结果a为0(想到a站在对++xb站在为++y && ++z )。 Similarly, for any expression 同样,对于任何表达

a && b 

a will be completely evaluated; a将被完全评估; b will not be evaluated unless the result of a is not 0. b将不会被评价除非的结果a不为0。

So for your case, the expression ++x is evaluated first. 因此,对于您的情况,首先计算表达式++x If the result is 0, only then will ++y && ++z be evaluated. 如果结果为0, 那么评估++y && ++z

|| 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 expression 例如,在表达式中

++x + ++y * ++z

the expressions ++x , ++y , and ++z may be evaluated in any order ; 表达式++x++y++z可以按任何顺序进行评估; all precedence tells you is that the result of (y+1) * (z+1) will be added to the result of x+1 . 所有优先级告诉你的是(y+1) * (z+1)的结果将被添加到x+1的结果中。

Top two answers explain it rather well... I'd point out that || 前两个答案很好地解释了......我会指出|| is "OrElse". 是“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. 如果右侧是假的,&&(AndAlso)的左侧不会被触及。

If you want both sides to get incremented, use | 如果您希望双方都增加,请使用| and &. 和&。

http://msdn.microsoft.com/en-us/library/2h9cz2eb(v=VS.80).aspx http://msdn.microsoft.com/en-us/library/2h9cz2eb(v=VS.80).aspx

A logical operation is said to be short-circuiting if the compiled code can bypass the evaluation of one expression depending on the result of another expression. 如果编译的代码可以根据另一个表达式的结果绕过一个表达式的评估,则称逻辑操作是短路的。 If the result of the first expression evaluated determines the final result of the operation, there is no need to evaluate the second expression, because it cannot change the final result. 如果第一个表达式求值的结果确定了操作的最终结果,则无需计算第二个表达式,因为它无法更改最终结果。 Short-circuiting can improve performance if the bypassed expression is complex, or if it involves procedure calls. 如果绕过的表达式很复杂,或者涉及过程调用,则短路可以提高性能。

MSDN has tables that show how parts are "(not evaluated)". MSDN有表格显示部分是如何“(未评估)”。

Why touch part 2, if Part 1 pre-determines the outcome deterministically? 如果第1部分确定性地预先确定结果,为什么要触摸第2部分?

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. 自从我使用C以来已经有很长一段时间了,但如果我没记错的话,++是一元运算符,它总是先于二元运算符。 Makes sense if you think about it. 如果你考虑它会有意义。

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. 无论如何b定义++ x意味着x必须在使用之前递增,因此你可以期望它在执行时具有高优先级。

No no no 不不不

if (++x || ++y && ++z) { /* ... */ }

Yes

 ++x; ++y; ++z; if (x || (y && z)) { /* ... */ } 

Edit after peer complaints :) 同行投诉后编辑 :)

YES! 是!

if (is_data_valid(x, y, z)) process_data(&x, &y, &z);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM