关于c ++:是否要求短路逻辑运算符?

Is short-circuiting logical operators mandated? And evaluation order?

ANSI标准是否规定逻辑运算符在C或C++中短路?

我很困惑,因为我记得K&R手册上说,您的代码不应该依赖于这些操作被短路,因为它们可能不会。有人能指出标准中说的逻辑运算总是短路的地方吗?我最感兴趣的是C++,C的答案也很棒。

我还记得我读到(不记得在哪里)评估顺序没有严格定义,所以您的代码不应该依赖或假定表达式中的函数将按特定的顺序执行:在语句的末尾,所有引用的函数都将被调用,但编译器可以自由选择最有效的顺序。

标准是否指明了该表达式的评估顺序?

1
if( functionA() && functionB() && functionC() ) cout<<"Hello world";


是的,在C和C++标准中,操作员需要EDCOX1、1和EDCOX1 0的短路和评估顺序。

C++标准说(C标准中应该有一个等价的子句):

1.9.18

In the evaluation of the following expressions

1
2
3
4
a &amp;&amp; b
a || b
a ? b : c
a , b

using the built-in meaning of the operators in these expressions, there is a sequence point after the evaluation of the first expression (12).

在C++中有一个额外的陷阱:短路不适用于过载运算符EDCOX1、1和EDCOX1×0的类型。

Footnote 12: The operators indicated in this paragraph are the built-in operators, as described in clause 5. When one of these operators is overloaded (clause 13) in a valid context, thus designating a user-defined operator function, the expression designates a function invocation, and the operands form an argument list, without an implied sequence point between them.

通常不建议在C++中重载这些运算符,除非您有一个非常特定的要求。您可以这样做,但它可能会破坏其他人代码中的预期行为,特别是如果这些运算符是通过实例化模板和类型重载这些运算符间接使用的。


短路评价和评价顺序是C和C++两种语言中规定的语义标准。

如果不是这样,像这样的代码就不是一个常见的习惯用法。

1
2
3
4
5
6
   char* pChar = 0;
   // some actions which may or may not set pChar to something
   if ((pChar != 0) && (*pChar != '\0')) {
      // do something useful

   }

第6.5.13节C99规范(PDF链接)的逻辑与运算符

(4). Unlike the bitwise binary & operator, the && operator guarantees
left-to-right evaluation; there is a
sequence point after the evaluation of
the first operand. If the first
operand compares equal to 0, the
second operand is not evaluated.

同样,第6.5.14节"逻辑或运算符"也指出

(4) Unlike the bitwise | operator, the ||
operator guarantees left-to-right
evaluation; there is a sequence point
after the evaluation of the first
operand. If the first operand compares
unequal to 0, the second operand is
not evaluated.

类似的措词可以在C++标准中找到,请在本草稿副本中检查第5.14节。正如checkers在另一个答案中指出的那样,如果重写&;&;或,则两个操作数必须在成为常规函数调用时进行计算。


是的,它要求(评估顺序和短路)。在您的示例中,如果所有函数都返回true,则调用的顺序严格按照functiona、functionb和functionc进行。像这样使用

1
2
3
if(ptr && ptr->value) {
    ...
}

逗号运算符相同:

1
2
3
// calls a, then b and evaluates to the value returned by b
// which is used to initialize c
int c = (a(), b());

一种说法是在&&||,的左右操作数之间以及?:的第一和第二/第三操作数之间是"序列点"。任何副作用在那一点之前都会被完全评估。所以,这是安全的:

1
2
int a = 0;
int b = (a++, a); // b initialized with 1, and a is 1

注意逗号运算符不能与用于分隔事物的语法逗号混淆:

1
2
// order of calls to a and b is unspecified!
function(a(), b());

C++标准在EDCOX1中表示:4:

The && operator groups left-to-right. The operands are both implicitly converted to type bool (clause 4).
The result is true if both operands are true and false otherwise. Unlike &, && guarantees left-to-right
evaluation: the second operand is not evaluated if the first operand is false.

5.15/1中:

The || operator groups left-to-right. The operands are both implicitly converted to bool (clause 4). It returns true if either of its operands is true, and false otherwise. Unlike |, || guarantees left-to-right evaluation; moreover, the second operand is not evaluated if the first operand evaluates to true.

旁边写着:

The result is a bool. All side effects of the first expression except for destruction of temporaries (12.2) happen before the second expression is evaluated.

除此之外,1.9/18

In the evaluation of each of the expressions

  • a && b
  • a || b
  • a ? b : C
  • a , b

using the built-in meaning of the operators in these expressions (5.14, 5.15, 5.16, 5.18), there is a sequence point after the evaluation of the first expression.


直接从老K&R:

C guarantees that && and || are evaluated left to right — we shall soon see cases where this matters.


非常小心。

对于基本类型,这些是快捷运算符。

但是,如果为自己的类或枚举类型定义这些运算符,它们就不是快捷方式。由于它们在这些不同情况下的用法存在语义差异,建议您不要定义这些运算符。

对于基本类型的operator &&operator ||,评估顺序是从左到右(否则很难进行短切):-,但是对于您定义的重载运算符,这些基本上是定义方法的语法糖,因此参数的评估顺序是不确定的。


你的问题归结为C++运算符优先性和关联性。基本上,在具有多个运算符且没有括号的表达式中,编译器通过遵循这些规则构造表达式树。

在优先权方面,当你有类似于A op1 B op2 C的东西时,你可以将它们分组为(A op1 B) op2 CA op1 (B op2 C)。如果op1的优先级高于op2,您将得到第一个表达式。否则,你会得到第二个。

对于关联性,当你有类似于A op B op C的东西时,你可以再次将thins分组为(A op B) op CA op (B op C)。如果op有左联想性,我们以第一个表达式结束。如果它有正确的结合性,我们就得到第二个。这也适用于具有相同优先级的运算符。

在这种特殊情况下,&&||具有更高的优先级,因此该表达式将被计算为(a !="" && it == seqMap.end()) || isEven

在表达式树窗体上,顺序本身是"从左到右"。所以我们首先评估a !="" && it == seqMap.end()。如果这是真的,那么整个表达式都是真的,否则我们就转到isEven。当然,过程在左子表达式中递归地重复自身。

有趣的消息,但优先权的概念有其数学符号的根源。同样的事情也发生在a*b + c中,其中*的优先级高于+

更有趣/更模糊的是,对于一个未分析的表达式A1 op1 A2 op2 ... opn-1 An,所有的运算符都具有相同的优先级,我们可以形成的二进制表达式树的数目由所谓的加泰罗尼亚数给出。对于大的n来说,它们生长得非常快。D


如果你相信维基百科:

[&& and ||] are semantically distinct from the bit-wise operators & and | because they will never evaluate the right operand if the result can be determined from the left alone

http://en.wikipedia.org/wiki/c_u(编程语言)特征