ANSI标准是否要求逻辑运算符在C或C中短路?
我很困惑,因为我记得K&R的书说你的代码不应该依赖于这些操作被短路,因为它们可能没有 . 有人可以指出标准中的哪个位置逻辑操作始终是短路的吗?我最感兴趣的是C,C的答案也很棒 .
我还记得读(不记得在哪里)评估顺序没有严格定义,所以你的代码不应该依赖或假设表达式中的函数将按特定的顺序执行:在语句的末尾所有引用的函数将被调用,但编译器可以自由选择最有效的顺序 .
标准是否表明该表达式的评估顺序?
if( functionA() && functionB() && functionC() ) cout<<"Hello world";
7 回答
如果您信任维基百科:
http://en.wikipedia.org/wiki/C_(programming_language)#Characteristics
是的,C和C标准中的操作员
||
和&&
都需要短路和评估顺序 .C标准说(C标准中应该有一个等价的条款):
在C中有一个额外的陷阱:短路确实 NOT 适用于超载运算符
||
和&&
的类型 .除非您有非常具体的要求,否则通常不建议在C中重载这些运算符 . 您可以这样做,但它可能会破坏其他人的代码中的预期行为,特别是如果通过实例化类型重载这些运算符的模板间接使用这些运算符 .
短路评估和评估顺序是C和C中的强制语义标准 .
如果不是这样,那么这样的代码就不是常见的习语
C99规范(PDF link)的第 6.5.13 Logical AND operator 节说
同样,第 6.5.14 Logical OR operator 节说
类似的措辞可以在C标准中找到,check section 5.14 in this draft copy . 正如跳棋在另一个答案中指出的那样,如果你重写&&或||,那么必须对两个操作数进行评估,因为它变成了常规函数调用 .
是的,它要求(评估顺序和短路) . 在您的示例中,如果所有函数都返回true,则调用的顺序严格来自functionA,然后是functionB,然后是functionC . 用于此类似
逗号运算符相同:
在
&&
,||
,,
的左右操作数之间以及?:
(条件运算符)的第一个和第二个/第三个操作数之间的一个是"sequence point" . 在此之前完全评估任何副作用 . 所以,这是安全的:请注意,不要将逗号运算符与用于分隔事物的语法逗号混淆:
C标准在_1125996中说:
并在
5.15/1
:它说两者都有旁边那些:
除此之外,
1.9/18
说直接来自古老的K&R:
要非常小心 .
对于POD类型,这些是快捷运算符 .
但是如果你为自己的类定义这些运算符,它们就不是捷径 . 由于在这些不同情况下它们的使用存在语义差异,因此建议您不要定义这些运算符 .
对于运算符&&和运算符||对于POD类型,评估顺序是从左到右(否则短切会很难:-)但是对于您定义的重载运算符,这些基本上是定义方法的语法糖,因此参数的评估顺序是不确定的 .
你的问题归结为C++ operator precedence和关联性 . 基本上,在具有多个运算符且没有括号的表达式中,编译器通过遵循这些规则来构造表达式树 .
对于优先级,当您有
A op1 B op2 C
之类的内容时,可以将事物分组为(A op1 B) op2 C
或A op1 (B op2 C)
. 如果op1
的优先级高于op2
,那么'll get the first expression. Otherwise, you'将获得第二个优先级 .对于关联性,当你有
A op B op C
之类的东西时,你可以再次将这些组分为(A op B) op C
或A op (B op C)
. 如果op
已离开关联,我们最终会得到第一个表达式 . 如果它具有正确的关联性,我们最终得到第二个 . 这也适用于具有相同优先级的操作员 .在这种特殊情况下,
&&
的优先级高于||
,因此表达式将被计算为(a != "" && it == seqMap.end()) || isEven
.订单本身在表达式树形式上是"left-to-right" . 所以我们首先评估
a != "" && it == seqMap.end()
. 如果确实整个表达式都是真的,否则我们转到isEven
. 当然,该过程在左子表达式内递归地重复 .有趣的花絮,但优先的概念源于数学符号 . 同样的事情发生在
a*b + c
中,其中*
的优先级高于+
.更有趣/模糊,对于不明显强调的表达式
A1 op1 A2 op2 ... opn-1 An
,其中所有运算符具有相同的优先级,我们可以形成的二进制表达式树的数量由所谓的Catalan numbers给出 . 对于大型n
,这些增长速度非常快 . d