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

发布于 2024-09-19 03:19:32 字数 121 浏览 5 评论 0 原文

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

Why does ++x || ++y && ++z calculate ++x first, even though the precedence of operator && is higher than ||?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

我只土不豪 2024-09-26 03:19:32

啊?

如果您说 &&|| 绑定更紧密 (这是正确的),则该表达式相当于

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

since || 短路,需要先评估左侧。

如果您的意思是它应该等效于

(++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.

风轻花落早 2024-09-26 03:19:32

由于 && 的优先级高于 ||,这意味着您的表达式相当于:

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

因此,在程序开始评估 & 的结果之前, &,它必须评估 ++x 以确定是否应该评估 || 的右侧操作数(逻辑二元运算符是“短” -电路”,这意味着如果左侧足以确定结果,则他们不会评估右侧)。这里没有什么可疑的或特定于编译器的内容。该表达式的行为由 C 标准精确指定,并且在任何编译器上都是相同的。如果 xyz 都是同一个变量,它甚至会起作用,因为 || 和 < code>& 引入序列点。

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 || 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 if x, y, and z were all the same variable, since || and && introduce sequence points.

檐上三寸雪 2024-09-26 03:19:32

放松R 和其他人已经解释了到底发生了什么。所以我补充一下:

你的问题的前提是错误的。 && 具有较高优先级这一事实并不意味着它周围的操作数必须在表达式中具有较低优先级的任何操作数之前进行计算。即使 ||&& 的特殊情况短路,情况也不一定如此。

例如,考虑a=b+c+d*e* 的优先级高于 +,但这并不意味着 d*e 必须在 b+c 之前计算代码>.它只是意味着在我们将乘积作为一个整体添加到表达式之前必须对其进行求值。编译器可以将此表达式计算为 temp1=d*etemp2=b+ca=temp1+temp2 或者它可以计算 <代码>temp1=b+c、temp2=d*ea=temp1+temp2。两者同样有效。

由于 ||&& 的短路行为,对计算顺序有一些额外的限制。


附带说明:一般来说,我会避免编写这样的代码。我可以很容易地看到另一个试图阅读这段代码的程序员对增量何时会发生以及何时不会发生感到困惑。好吧,也许如果你使用真正的变量名,它看起来就不会那么奇怪了。

我偶尔会依靠短路来防止副作用。就像

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

我依靠短路来防止读取(如果我们已经在文件末尾),或者

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

我依靠第一个测试来短路 false,所以我不应该执行删除操作t。但这些例子对我来说似乎非常简单,我希望任何有能力的程序员都能看到我在做什么。但当这些例子变得晦涩难懂时,我认为需要对其进行解释。考虑

if (customerType==RETAIL || lastDepositAmount()>100.00)

如果 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 that d*e must be evaluated before b+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 as temp1=d*e, temp2=b+c, a=temp1+temp2 or it could evaluate temp1=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

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. 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".

故事与诗 2024-09-26 03:19:32

这里有非常错误的答案。

此表达式的求值顺序与实现无关。这是明确定义的!

由于 && 绑定高于 ||,因此该表达式等效于 ++x || (++y && ++z)。此外,&&|| 都是短路的,因此如果表达式的左侧足以确定值,右侧从不评估。

什么时候有这样的情况呢?好吧,我们知道 False &&无论 a 的值是什么,a 始终解析为 False,特别是即使 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 to False, no matter the value of a, in particular even if a is not a single value but instead a complex expression. Therefore we don’t evaluate a at all. Likewise, True || a always resolves to 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.

谁与争疯 2024-09-26 03:19:32

如图所示,使用波兰树数据结构对运算符进行评估,这是一种深度优先的评估算法。
让我们为操作命名:
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.

alt text

-小熊_ 2024-09-26 03:19:32

++ 具有最高优先级,因为它的 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.

拔了角的鹿 2024-09-26 03:19:32

优先级和求值顺序不是一回事,尤其是在这种情况下。所有优先级告诉您表达式应该被解析为

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

IOW,这意味着进行 OR 运算的表达式是 ++x(++y && ++z )。它意味着(++y && ++z)将在++x之前评估代码>.

对于逻辑运算符 ||&&,计算始终从左到右(在线 C 标准,第 6.5.13 和 6.5.14 节)。对于任何表达式

a || b

a 都将被完全求值;除非 a 的结果为 0,否则 b 不会被计算(想想 a 代表 ++xb代表++y && ++z)。类似地,对于任何表达式

a && b 

a 都将被完全求值;除非 a 的结果不为 0,否则 b 不会被求值。

因此,对于您的情况,首先对表达式 ++x 求值。如果结果为 0,只有才会++y && ++z 被评估。

||&& 的特殊之处在于,保证计算顺序是从左到右。对于按位运算符或算术运算符来说,情况并非如此。例如,在表达式中,

++x + ++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

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

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 expression

a || b

a will be completely evaluated; 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). Similarly, for any expression

a && b 

a will be completely evaluated; b will not be evaluated unless the result of a 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 expression

++x + ++y * ++z

the 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 of x+1.

凉宸 2024-09-26 03:19:32

前两个答案很好地解释了这一点......我想指出 ||是“否则”。

如果左侧为真,则右侧不会被触及。 && 的左侧如果右侧为 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

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)".

Why touch part 2, if Part 1 pre-determines the outcome deterministically?

笑饮青盏花 2024-09-26 03:19:32

我已经很久没有使用 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.

只怪假的太真实 2024-09-26 03:19:32

如果您的操作对顺序敏感,则不应依赖感知的运算符优先级,因为不同的编译器(以及同一编译器的不同版本)可能会以不同的方式实现优先级。

不管怎样,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.

南冥有猫 2024-09-26 03:19:32

不不不

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

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

在同行投诉后编辑:)

是的!

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

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文