在 C++ 中,为什么 true && true || 假&&假==真?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4061927/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In C++, why does true && true || false && false == true?
提问by Andrew
I'd like to know if someone knows the way a compiler would interpret the following code:
我想知道是否有人知道编译器解释以下代码的方式:
#include <iostream>
using namespace std;
int main() {
cout << (true && true || false && false) << endl; // true
}
Is this true because && has a higher precedence than || or because || is a short-circuit operator (in other words, does a short circuit operator disregard all subsequent expressions, or just the next expression)?
这是真的吗,因为 && 的优先级高于 || 或因为 || 是短路运算符(换句话说,短路运算符是否忽略所有后续表达式,或仅忽略下一个表达式)?
回答by AngelLeliel
&&
has a higher precedence than ||
.
&&
具有比 更高的优先级||
。
回答by Antal Spector-Zabusky
Caladainhas exactly the right answer, but I wanted to respond to one of your comments on his answer:
Caladain的答案完全正确,但我想回应您对他的回答的评论之一:
If short-circuiting the || operator occurs and short-circuits the execution of the second && expression, that means the || operator was executed BEFORE the second && operator. This implies left-to-right execution for && and || (not && precedence).
如果短路 || 运算符发生并短路第二个 && 表达式的执行,这意味着 || 运算符在第二个 && 运算符之前执行。这意味着 && 和 || 从左到右执行 (不是&&优先)。
I think part of the problem you're having is that precedence doesn't quite mean what you think it means. It is true that &&
has higher precedence than ||
, and this exactly accounts for the behavior you're seeing. Consider the case with ordinary arithmetic operators: suppose we have a * b + c * (d + e)
. What precedence tells us is how to insert parentheses: first around *
, then around +
. This gives us (a * b) + (c * (d + e))
; in your case, we have (1 && 1) || (infiniteLoop() && infiniteLoop())
. Then, imagine the expressions becoming trees. To do this, transform each operator into a node with its two arguments as children:
我认为您遇到的部分问题是优先级并不完全意味着您认为它的含义。确实&&
比 具有更高的优先级||
,这正是您所看到的行为的原因。考虑普通算术运算符的情况:假设我们有a * b + c * (d + e)
。优先级告诉我们如何插入括号:首先是 around *
,然后是 around +
。这给了我们(a * b) + (c * (d + e))
; 在你的情况下,我们有(1 && 1) || (infiniteLoop() && infiniteLoop())
。然后,想象这些表情变成了树。为此,将每个运算符转换为一个节点,其两个参数作为子节点:
Evaluating this tree is where short-circuiting comes in. In the arithmetic tree, you can imagine a breadth-first bottom-up execution style: first evaluate DE = d + e
, then AB = a * b
and CDE = c * DE
, and the final result is AB + CDE
. But note that you could equallywell have evaluated AB
first, then DE
, CDE
, and the final result; you can't tell the difference. However, since ||
and &&
are short-circuiting, they haveto use this leftmost-first evaluation. Thus, to evaluate the ||
, we first evaluate 1 && 1
. Since this is true, ||
short-circuits and ignores its right-hand branch—even though, ifit had evaluated it, it would have had to evaluate the infiniteLoop() && infiniteLoop()
first.
评估这棵树就是短路进来。在运算树,你能想象一个广度优先自下而上的执行风格:先评估DE = d + e
,再AB = a * b
和CDE = c * DE
,最终的结果是AB + CDE
。但请注意,您同样可以先求值AB
,然后DE
是CDE
、 和最终结果;你分不出区别。然而,由于||
和&&
是短路的,他们必须使用这个最左优先的评估。因此,为了评估||
,我们首先评估1 && 1
。由于这是真的,||
短路和忽略其右支路-尽管,如果它评估了它,就不得不评估infiniteLoop() && infiniteLoop()
第一的。
If it helps, you can think of each node in the tree as a function call, which produces the following representation plus(times(a,b), times(c,plus(d,e)))
in the first case, and or(and(1,1), and(infiniteLoop(),infiniteLoop())
in the second case. Short-circuiting means that you have to fully evaluate each left-hand function argument to or
or and
; if it's true
(for or
) or false
(for and
), then ignore the right-hand argument.
如果有帮助,您可以将树中的每个节点视为一个函数调用,它plus(times(a,b), times(c,plus(d,e)))
在第一种情况和or(and(1,1), and(infiniteLoop(),infiniteLoop())
第二种情况下产生以下表示。短路意味着您必须将每个左侧函数参数完全评估为or
or and
;如果是true
(for or
) 或false
(for and
),则忽略右边的参数。
Your comment presupposes that we evaluate everything with highest precedence first, then everything with next-highest precedence, and so on and so forth, which corresponds to a breadth-first bottom-up execution of the tree. Instead, what happens is that precedence tells us how to build the tree. The rules for execution of the tree are irrelevant in the simple arithmetic case; short-circuiting, however, is precisely an exact specification of how to evaluate the tree.
您的评论假定我们首先评估具有最高优先级的所有内容,然后是具有次高优先级的所有内容,依此类推,这对应于树的广度优先自底向上执行。相反,发生的是优先级告诉我们如何构建树。树的执行规则与简单算术情况无关;然而,短路正是如何评估树的精确规范。
Edit 1:In one of your other comments, you said
编辑 1:在您的其他评论之一中,您说
Your arithmetic example necessitates the two multiplications to be evaluated before the final addition, is that not what defines precedence?
您的算术示例需要在最终加法之前评估两次乘法,这不是定义优先级的原因吗?
Yes, this is what defines precedence—except it's not quite true. It's certainly exactly true in C, but consider how you would evaluate the (non-C!) expression 0 * 5 ^ 7
in your head, where 5 ^ 7 = 57
and ^
has higher precedence than *
. According to your breadth-first bottom-up rule, we need to evaluate 0
and 5 ^ 7
before we can find the result. But you wouldn't bother to evaluate 5 ^ 7
; you'd just say "well, since 0 * x = 0
for all x
, this must be 0
", and skip the whole right-hand branch. In other words, I haven't evaluated both sides fully before evaluating the final multiplication; I've short-circuited. Similarly, since false && _ == false
and true || _ == true
for any _
, we may not need to touch the right-hand side; this is what it means for an operator to be short-circuiting. C doesn't short-circuit multiplication (although a language could do this), but it doesshort-circuit &&
and ||
.
是的,这就是优先级的定义——除非它不完全正确。这在C 中当然完全正确,但请考虑如何0 * 5 ^ 7
在脑海中评估(非 C!)表达式,其中和 的优先级高于. 根据你的广度优先自下而上的规则,我们需要评估,然后才能找到结果。但你不会费心去评估;你只需说“好吧,因为对于所有人来说,这一定是”,然后跳过整个右手边的分支。换句话说,在评估最终乘法之前,我还没有完全评估双方;我短路了 类似地,由于和对于任何5 ^ 7 = 57
^
*
0
5 ^ 7
5 ^ 7
0 * x = 0
x
0
false && _ == false
true || _ == true
_
,我们可能不需要触摸右侧;这就是操作员短路的含义。C 不会短路乘法(尽管语言可以做到这一点),但它会短路&&
和||
。
Just as short-circuiting 0 * 5 ^ 7
doesn't change the usual PEMDAS precedence rules, short-circuiting the logical operators doesn't change the fact that &&
has higher precedence than ||
. It's simply a shortcut. Since we have to choose someside of the operator to evaluate first, C promises to evaluate the left-hand side of the logical operators first; once it's done this, there's an obvious (and useful) way to avoid evaluating the right-hand side for certain values, and C promises to do this.
正如短路0 * 5 ^ 7
不会改变通常的 PEMDAS 优先级规则一样,将逻辑运算符短路也不会改变&&
优先级高于||
. 这只是一个捷径。由于我们必须先选择运算符的某一侧进行计算,C 承诺首先计算逻辑运算符的左侧;一旦完成,就有一种明显(且有用)的方法来避免评估某些值的右侧,而 C 承诺会这样做。
Your rule—evaluate the expression breadth-first bottom-up—is also well-defined, and a language could choose to do this. However, it has the disadvantage of not permitting short-circuiting, which is a useful behavior. But if every expression in your tree is well-defined (no loops) and pure (no modifying variables, printing, etc.), then you can't tell the difference. It's only in these strange cases, which the mathematical definitions of "and" and "or" don't cover, that short-circuiting is even visible.
你的规则——评估表达式广度优先自下而上——也是明确定义的,一种语言可以选择这样做。但是,它的缺点是不允许短路,这是一种有用的行为。但是,如果树中的每个表达式都是明确定义的(没有循环)并且是纯的(没有修改变量、打印等),那么您就无法区分。只有在这些奇怪的情况下,“和”和“或”的数学定义没有涵盖,短路甚至是可见的。
Also, note that there's nothing fundamentalabout the fact that short-circuiting works by prioritizing the leftmost expression. One could define a language ?, where ??
represents and
and \\
represents ||
, but where 0 ?? infiniteLoop()
and 1 \\ infiniteLoop()
would loop, and infiniteLoop() ?? 0
and infiniteLoop() \\ 1
would be false and true, respectively. This just corresponds to choosing to evaluate the right-hand side first instead of the left-hand side, and then simplifying in the same way.
另外,请注意,短路通过优先考虑最左边的表达式这一事实没有任何根本性的意义。可以定义一种语言 ?,其中??
代表and
和\\
代表||
,但 where0 ?? infiniteLoop()
和1 \\ infiniteLoop()
will 循环,and infiniteLoop() ?? 0
andinfiniteLoop() \\ 1
分别为 false 和 true。这只是对应于选择首先评估右侧而不是左侧,然后以相同的方式进行简化。
In a nutshell:what precedence tells us is how to build the parse tree. The only sensible orders for evaluating the parse tree are those that behave as ifwe evaluate it breadth-first bottom-up (as you want to do) on well-defined pure values. For undefined or impure values, somelinear order must be chosen.1Once a linear order is chosen, certain values for one side of an operator may uniquely determine the result of the whole expression (e.g., 0 * _ == _ * 0 == 0
, false && _ == _ && false == false
, or true || _ == _ || true == true
). Because of this, you may be able to get away without completing the evaluation of whatever comes afterwards in the linear order; C promises to do this for the logical operators &&
and ||
by evaluating them in a left-to-right fashion, and not to do it for anything else. However, thanks to precedence, we doknow that true || true && false
is true
and not false
: because
简而言之:优先级告诉我们如何构建解析树。评估解析树的唯一合理顺序是那些表现得好像我们在定义明确的纯值上评估它的广度优先自下而上(如您所愿)。对于未定义或不纯的值,必须选择某种线性顺序。1一旦选择了线性顺序,运算符一侧的某些值可以唯一地确定整个表达式的结果(例如、0 * _ == _ * 0 == 0
、false && _ == _ && false == false
、 或true || _ == _ || true == true
)。因此,您可能无需完成对线性顺序之后发生的任何事情的评估就可以逃脱;C 承诺为逻辑运算符&&
和||
通过以从左到右的方式评估它们,而不是为了其他任何东西。但是,由于优先级,我们确实知道这true || true && false
是true
不是false
:因为
true || true && false
→ true || (true && false)
→ true || false
→ true
instead of
代替
true || true && false
? (true || true) && false
→ true && false
→ false
1:Actually, we could also theoretically evaluate both sides of an operator in parallel, but that's not important right now, and certainly wouldn't make sense for C. This gives rise to more flexible semantics, but one which has problems with side-effects (when do they happen?).
1:实际上,我们理论上也可以并行计算运算符的两边,但这现在并不重要,而且对于 C 肯定没有意义。这产生了更灵活的语义,但在边上存在问题-效果(它们什么时候发生?)。
回答by Caladain
(true && true || false && false) is evaluated with && having higher precedence.
(true && true || false && false) 以 && 具有更高的优先级进行评估。
TRUE && TRUE = True
FALSE && FALSE = False
True || False = True
Update:
更新:
1&&1||infiniteLoop()&&infiniteLoop()
Why does this produce true in C++?
为什么这会在 C++ 中产生 true?
Like before, lets break it apart. && has higher precedence that || and boolean statements short circuit in C++.
像以前一样,让我们把它分开。&& 的优先级高于 || 和布尔语句在 C++ 中短路。
1 && 1 = True.
When a bool value is converted to an integer value, then
当 bool 值转换为整数值时,则
false -> 0
true -> 1
The expression evaluates this (true) && (true) statement, which short circuits the ||, which prevents the infinite loops from running. There's a lot more compiler Juju going on, so this is a simplistic view of the situation which is adequate for this example.
该表达式计算此 (true) && (true) 语句,该语句使 || 短路,从而阻止无限循环运行。有更多的编译器 Juju 在运行,所以这是一个简单的情况视图,对于这个例子来说已经足够了。
In a NON-short circuited environment, That expression would hang forever because both sides of the OR would be "evaluated" and the right side would hang.
在非短路环境中,该表达式将永远挂起,因为 OR 的两侧都将被“评估”而右侧将挂起。
If you're confused about the precedence, this is how things would evaluate in your original post if || had higher precedence than &&:
如果您对优先级感到困惑,这就是您原始帖子中的评估方式 if || 具有比 && 更高的优先级:
1st.) True || False = True
2nd.) True && 1st = True
3rd.) 2nd && false = false
Expression = False;
I can't remember if it goes right to left, or left to right, but either way the result would be the same. In your second post, if || had higher precendence:
我不记得是从右到左还是从左到右,但无论哪种方式,结果都是一样的。在你的第二篇文章中,如果 || 有更高的优先级:
1st.) 1||InfLoop(); Hang forever, but assuming it didn't
2nd.) 1 && 1st;
3rd.) 2nd && InfLoop(); Hang Forever
tl;dr:It's still precedence that's making the &&'s be evaluated first, but the compiler short circuits the OR as well. In essence, the compiler groups the order of operations like this (SIMPLISTIC VIEW, put downthe pitchforks :-P)
tl; dr:首先评估 && 仍然是优先级,但编译器也会使 OR 短路。从本质上讲,编译组这样的操作顺序(简单地认为,把倒在叉子:-P)
1st.) Is 1&&1 True?
2nd.) Evaluate if the Left side of the operation is true,
if so, skip the second test and return True,
Otherwise return the value of the second test(this is the OR)
3rd.) Is Inf() && Inf() True? (this would hang forever since
you have an infinite loop)
Update #2:"However, this example proves && DOES NOT have precedence, as the || is evaluated before the second &&. This shows that && and || have equal precedence and are evaluated in left-to-right order."
更新 #2:“然而,这个例子证明 && 没有优先级,因为 || 在第二个 && 之前被评估。这表明 && 和 || 具有相同的优先级,并按从左到右的顺序进行评估。”
"If && had precedence it would evaluate the first && (1), then the second && (infinite loops) and hang the program. Since this does not happen, && is not evaluated before ||."
“如果 && 有优先级,它会评估第一个 && (1),然后是第二个 &&(无限循环)并挂起程序。由于这不会发生,&& 不会在 || 之前进行评估。”
Let's cover these in detail.
让我们详细介绍这些。
We're talking about two distinct things here. Precedence, which determines the Order of Operations, and Short Circuiting, which is a compiler/language trick to save processor cycles.
我们在这里谈论两个不同的事情。确定操作顺序的优先级和短路,这是一种节省处理器周期的编译器/语言技巧。
Let's cover Precedence first. Precedence is short hand for "Order of Operations" In essence, given this statement: 1 + 2 * 3 in which order should the operations be grouped for evaluation?
让我们先介绍优先级。优先级是“操作顺序”的简写本质上,鉴于此语句: 1 + 2 * 3 应按哪种顺序对操作进行分组以进行评估?
Mathematics clearly defines the order of operations as giving multiplication higher precedence than addition.
数学清楚地将运算顺序定义为乘法优先于加法。
1 + (2 * 3) = 1 + 2 * 3
2 * 3 is evaluated first, and then 1 is added to the result.
* has higher precedence than +, thus that operation is evaluated first.
Now, lets transition to boolean expressions: (&& = AND, || = OR)
现在,让我们转换到布尔表达式:(&& = AND, || = OR)
true AND false OR true
C++ gives AND a higher precedence than OR, thus
C++ 赋予 AND 比 OR 更高的优先级,因此
(true AND false) OR true
true AND false is evaluated first, and then
used as the left hand for the OR statement
So, just on precedence, (true && true || false && false) will be operated on in this order:
因此,只是在优先级上, (true && true || false && false) 将按以下顺序操作:
((true && true) || (false && false)) = (true && true || false && false)
1st Comparison.) true && true
2nd Comparison.) false && false
3rd Comparison.) Result of 1st comparison || Result of Second
With me thus far? Now lets get into Short Circuiting: In C++, Boolean statements are what's called "short circuited". This means that the compiler will look at a given statement a choose the "best path" for evaluation. Take this example:
和我到此为止?现在让我们进入短路:在 C++ 中,布尔语句就是所谓的“短路”。这意味着编译器将查看给定语句并选择“最佳路径”进行评估。拿这个例子:
(true && true) || (false && false)
There is no need to evaluate the (false && false) if (true && true)
equals true, since only one side of the OR statement needs to be true.
Thus, the compiler will Short Circuit the expression. Here's the compiler's
Simplified logic:
1st.) Is (true && true) True?
2nd.) Evaluate if the Left side of the operation is true,
if so, skip the second test and return True,
Otherwise return the value of the second test(this is the OR)
3rd.) Is (false && false) True? Return this value
As you can see, if (true && true) is evaluated TRUE, then there isn't a need to spend the clock cycles evaluating if (false && false) is true.
如您所见,如果 (true && true) 被评估为 TRUE,则无需花费时钟周期来评估 (false && false) 是否为真。
C++ Always short Circuts, but other languages provide mechanisms for what are called "Eager" operators.
C++ 总是短路电路,但其他语言为所谓的“急切”运算符提供了机制。
Take for instance the programming language Ada. In Ada, "AND" and "OR" are "Eager" Operators..they force everything to be evaluated.
以编程语言 Ada 为例。在 Ada 中,“AND”和“OR”是“Eager”运算符……它们强制对所有内容进行评估。
In Ada (true AND true) OR (false AND false) would evaluate both (true AND true) and (false AND false) before evaluating the OR. Ada Also gives you the ability to short circuit with AND THEN and OR ELSE, which will give you the same behavior C++ does.
在 Ada 中 (true AND true) OR (false AND false) 将在评估 OR 之前评估 (true AND true) 和 (false AND false)。Ada 还使您能够使用 AND THEN 和 OR ELSE 进行短路,这将为您提供与 C++ 相同的行为。
I hope that fully answers your question. If not, let me know :-)
我希望能完全回答你的问题。如果没有,请告诉我:-)
Update 3:Last update, and then I'll continue on email if you're still having issues.
更新 3:上次更新,如果您仍有问题,我会继续发送电子邮件。
"If short-circuiting the || operator occurs and short-circuits the execution of the second && expression, that means the || operator was executed BEFORE the second && operator. This implies left-to-right execution for && and || (not && precedence)."
“如果短路 || 运算符发生并使第二个 && 表达式的执行短路,则意味着 || 运算符在第二个 && 运算符之前执行。这意味着 && 和 || 的从左到右执行(不是&&优先)。”
Let's look at then this example:
让我们看看这个例子:
(false && infLoop()) || (true && true) = true (Put a breakpoint in InfLoop and it won't get hit)
false && infLoop() || true && true = true (Put a breakpoint in InfLoop and it won't get hit)
false || (false && true && infLoop()) || true = false (infLoop doesn't get hit)
If what you were saying was true, InfLoop would get hit in the first two. You'll also notice InfLoop() doesn't get called in the third example either.
如果你说的是真的,InfLoop 会在前两个中被击中。您还会注意到 InfLoop() 在第三个示例中也没有被调用。
Now, lets look at this:
现在,让我们看看这个:
(false || true && infLoop() || true);
Infloop gets called! If OR had higher precendence than &&, then the compiler would evaluate:
Infloop 被调用!如果 OR 的优先级高于 && ,则编译器将评估:
(false || true) && (infLoop() || true) = true;
(false || true) =true
(infLoop() || true = true (infLoop isn't called)
But InfLoop gets called! This is why:
但是 InfLoop 被调用了!这就是为什么:
(false || true && infLoop() || true);
1st Comparison.) true && InfLoop() (InfLoop gets called)
2nd Comparison.) False || 1st Comp (will never get here)
3rd Comparison.) 2nd Comp || true; (will never get here)
Precendece ONLY sets the grouping of operations. In this, && is greater than ||.
Precendce ONLY 设置操作分组。其中,&& 大于 ||。
true && false || true && true gets grouped as
(true && false) || (true && true);
The Compiler Thencomes along and determines what order it should execute the evaluation in to give it the best chance for saving cycles.
编译器然后出现并确定它应该以什么顺序执行评估以给它节省周期的最佳机会。
Consider: false && infLoop() || true && true
Precedence Grouping goes like this:
(false && infLoop()) || (true && true)
The compiler then looks at it, and decides it will order the execution in this order:
(true && true) THEN || THEN (false && InfLoop())
It's kindof a fact..and I don't know how else to demonstrate this. Precedence is determined by the language grammar rules. The Compiler's optimization is determined by each compiler..some are better than others, but Allare free to reorder the grouped comparisons as it sees fit in order to give it the "best" chance for the fastest execution with the fewest comparisons.
这是一个事实......我不知道如何证明这一点。优先级由语言语法规则决定。Compiler 的优化由每个编译器决定......有些比其他的更好,但所有人都可以自由地按照它认为合适的方式对分组比较进行重新排序,以便为它提供“最佳”机会以最少的比较实现最快的执行。
回答by Ignacio Vazquez-Abrams
&&
does indeed have a higher precedence.
&&
确实有更高的优先级。
回答by RBerteig
Two facts explain the behavior of both examples. First, the precedence of &&
is higher than ||
. Second, both logical operators use short-circuit evaluation.
两个事实解释了这两个示例的行为。首先, 的优先级 &&
高于||
。其次,两个逻辑运算符都使用短路评估。
Precedence is often confounded with order of evaluation, but it is independent. An expression may have its individual elements evaluated in any order, as long as the final result is correct. In general for some operator, that means that the value on the left (LHS) may be evaluated either before or after the value on the right (RHS), as long as both are evaluated before the operator itself is applied.
优先级经常与求值顺序混淆,但它是独立的。只要最终结果是正确的,表达式就可以按任何顺序计算其各个元素。一般来说,对于某些运算符,这意味着左边的值 (LHS) 可以在右边的值 (RHS) 之前或之后计算,只要在应用运算符本身之前计算两者即可。
The logical operators have a special property: in certain cases if one side evaluates to a specific value, then the operator's value is known regardless of the value on the other side. To make this property useful, the C language (and by extension every C-like language) has specified the logical operators to evaluate the LHS before the RHS, and further to only evaluate the RHS if its value is requiredto know the result of the operator.
逻辑运算符有一个特殊的属性:在某些情况下,如果一侧计算为特定值,则无论另一侧的值如何,都可以知道运算符的值。为了使这一特性非常有用,C语言(通过扩展每一类C语言)已指定的逻辑运算符的LHS评价RHS之前,进一步只有在其价值评估RHS需要知道的结果操作员。
So, assuming the usual definitions of TRUE
and FALSE
, TRUE && TRUE || FALSE && FALSE
is evaluated starting at the left. The first TRUE
doesn't force the result of the first &&
, so the second TRUE
is evaluated, and then the expression TRUE && TRUE
is evaluated (to TRUE). Now, the ||
knows its LHS. Even better, its LHS has forced the result of the ||
to be known, so it skips evaluation of its entire RHS.
因此,假设通常的定义TRUE
和FALSE
,TRUE && TRUE || FALSE && FALSE
是在左求开始。第一个TRUE
不强制第一个的结果&&
,因此计算第二个TRUE
,然后计算表达式TRUE && TRUE
(为 TRUE)。现在,||
知道它的 LHS。更好的是,它的 LHS 已经强制||
知道了 的结果,因此它跳过了对整个 RHS 的评估。
The exact same order of evaluation applies in the second case. Since the RHS of the ||
is irrelevant, it isn't evaluated and neither call to infiniteLoop()
is made.
完全相同的评估顺序适用于第二种情况。由于 的 RHS ||
无关紧要,因此不会对其进行评估,也不会调用 to infiniteLoop()
。
This behavior is by design, and is useful. For instance, you can write p && p->next
knowing that the expression will never attempt to dereference a NULL pointer.
此行为是设计使然,很有用。例如,您可以编写p && p->next
知道表达式永远不会尝试取消引用 NULL 指针。
回答by Anonymoose
"If short-circuiting the || operator occurs and short-circuits the execution of the second && expression, that means the || operator was executed BEFORE the second && operator. This implies left-to-right execution for && and || (not && precedence)."
“如果短路 || 运算符发生并使第二个 && 表达式的执行短路,则意味着 || 运算符在第二个 && 运算符之前执行。这意味着 && 和 || 的从左到右执行(不是&&优先)。”
Not quite.
不完全的。
(xx && yy || zz && qq)
Would be evaluated like this:
会这样评价:
- Check first operator.
- Evaluate
xx && yy
- Check next operator.
- If next operator is
||
, and the first part of the statement is true, skip the rest. - Otherwise, check for next operator after
||
, and evaluate it:zz && qq
- Finally, evaluate
||
.
- 检查第一个操作员。
- 评估
xx && yy
- 检查下一个运算符。
- 如果下一个运算符是
||
,并且语句的第一部分为真,则跳过其余部分。 - 否则,在 之后检查下一个运算符
||
,并对其进行评估:zz && qq
- 最后,评价
||
。
From my understanding, C++ is designed so that it reads things in before it begins evaluating. After all, in our example, it doesn't know that we have a second &&
check after the ||
until it reads it in, meaning it has to read in the ||
before it gets to the second &&
. As such, if the first part evaluated to true, it won't do the part after the ||
, but if the first part evaluates to false, then it'll do the first part, read in the ||
, find and evaluate the second part, and use the second part's result to determine the final result.
根据我的理解,C++ 的设计使其在开始评估之前先读入内容。毕竟,在我们的示例中,它不知道我们在 之后进行了第二次&&
检查,||
直到它读入它,这意味着它必须在||
到达第二个 之前读入&&
。因此,如果第一部分评估为真,则不会执行 之后的部分||
,但如果第一部分评估为假,则它将执行第一部分,读入||
,查找并评估第二部分,并使用第二部分的结果来确定最终结果。
回答by Cheers and hth. - Alf
Regarding Andrew's latest code,
关于安德鲁的最新代码,
#include <iostream>
using namespace std;
bool infiniteLoop () {
while (true);
return false;
}
int main() {
cout << (true && true || infiniteLoop() && infiniteLoop()) << endl; // true
}
Short-circuit evaluation means that the calls to infiniteLoop
are guaranteed to not be executed.
短路评估意味着infiniteLoop
保证不会执行对 的调用。
However, it's interesting in a perverse sort of way because the C++0x draft makes the infinite-loop-that-does-nothing Undefined Behavior. That new rule is generally regarded as very undesirable and stupid, even downright dangerous, but it sort of sneaked into the draft. Partially from considerations of threading scenarios, where the author of one paper thought it would simplify the rules for something-or-other pretty irrelevant.
然而,它以一种反常的方式很有趣,因为 C++0x 草案使无限循环无所作为Undefined Behavior。这条新规则通常被认为是非常不受欢迎和愚蠢的,甚至是彻头彻尾的危险,但它有点偷偷溜进了草案。部分是出于对线程场景的考虑,其中一篇论文的作者认为它会简化一些非常不相关的规则。
So, with a compiler that's on the "leading edge" of C++0x-conformance the program could terminate, with someresult, even if it executed a call to infiniteLoop
! Of course, with such a compiler it could also produce that dreaded phenomenon, nasal daemons...
所以,用一个编译器,它是对的C ++ 0x的不合格的“前沿”的计划可能终止,与一些结果,即使执行调用infiniteLoop
!当然,有了这样的编译器,它也可能产生可怕的现象,鼻守护进程……
Happily, as mentioned, short-circuit evaluation means that the calls are guaranteed to not be executed.
令人高兴的是,如上所述,短路评估意味着保证不会执行调用。
Cheers & hth.,
干杯 & hth.,
回答by Macke
Since and/or/true/false is very similar to */+/1/0 (they are mathematically equivalent-ish), the following is also true:
由于 and/or/true/false 与 */+/1/0 非常相似(它们在数学上是等价的),以下也是正确的:
1 * 1 + 0 * 0 == 1
and rather easy to remember...
而且很容易记住...
So yes, it has to do with precedence andshort-circuit. Precendence of boolean ops is rather easy if you map it to their corresponding integer ops.
所以是的,它与优先级和短路有关。如果将布尔操作映射到相应的整数操作,则布尔操作的优先级相当容易。
回答by Philipp
regarding your edit: infiniteLoop() won't be evaluated because true || (whatever) is always true. Use true | (whatever) if whatever should be executed.
关于您的编辑:infiniteLoop() 不会被评估,因为 true || (无论如何)总是正确的。使用真| (无论如何)如果应该执行什么。
回答by filipe
about the true && true || infiniteLoop() && infiniteLoop()
example, neither of the infinite loop calls are being evaluated because of the two characteristics combined: && has precedence over ||, and || short-circuits when the left side is true.
关于这个true && true || infiniteLoop() && infiniteLoop()
例子,由于两个特征的结合,两个无限循环调用都没有被评估:&&优先于||,和|| 当左侧为真时短路。
if && and || had the same precedence, the evaluation would have to go like this:
如果 && 和 || 具有相同的优先级,评估必须是这样的:
((( true && true ) || infiniteLoop ) && infiniteLoop )
(( true || infiniteLoop ) && infiniteLoop )
=> first call to infiniteLoop is short-circuited
(true && infiniteLoop) => second call to infiniteLoop would have to be evaluated
but because of &&'s precedence, the evaluation actually goes
但由于 && 的优先级,评估实际上是
(( true && true ) || ( infiniteLoop && infiniteLoop ))
( true || ( infiniteLoop && infiniteLoop ))
=> the entire ( infiniteLoop && infiniteLoop ) expression is short circuited
( true )