ANSI标准是否要求逻辑运算符在C或C++中被短路?
我很困惑,因为我记得K&R的书说你的代码不应该依赖于这些操作被短路,因为它们可能没有.有人可以指出标准中的哪个位置逻辑操作始终是短路的吗?我最感兴趣的是C++,C的答案也很棒.
我还记得读(不记得在哪里)评估顺序没有严格定义,所以你的代码不应该依赖或假设表达式中的函数将按特定的顺序执行:在语句的末尾所有引用的函数将被调用,但编译器可以自由选择最有效的顺序.
标准是否表明该表达式的评估顺序?
if( functionA() && functionB() && functionC() ) cout<<"Hello world";
Alex B.. 147
是的,运营商||
以及&&
C和C++标准都需要短路和评估顺序.
C++标准说(C标准中应该有一个等价的子句):
1.9.18
在评估以下表达式时
a && b a || b a ? b : c a , b使用这些表达式中运算符的内置含义,在评估第一个表达式(12)之后有一个序列点.
在C++中有一个多余的陷阱:短路确实不适用于重载操作类型||
和&&
.
脚注12:本段中指示的运算符是内置运算符,如第5节所述.当其中一个运算符在有效上下文中重载(第13节),从而指定用户定义的运算符函数时,表达式指定一个函数调用,操作数形成一个参数列表,它们之间没有隐含的序列点.
除非您有非常具体的要求,否则通常不建议在C++中重载这些运算符.您可以这样做,但它可能会破坏其他人的代码中的预期行为,特别是如果通过实例化类型重载这些运算符的模板间接使用这些运算符.
是的,运营商||
以及&&
C和C++标准都需要短路和评估顺序.
C++标准说(C标准中应该有一个等价的子句):
1.9.18
在评估以下表达式时
a && b a || b a ? b : c a , b使用这些表达式中运算符的内置含义,在评估第一个表达式(12)之后有一个序列点.
在C++中有一个多余的陷阱:短路确实不适用于重载操作类型||
和&&
.
脚注12:本段中指示的运算符是内置运算符,如第5节所述.当其中一个运算符在有效上下文中重载(第13节),从而指定用户定义的运算符函数时,表达式指定一个函数调用,操作数形成一个参数列表,它们之间没有隐含的序列点.
除非您有非常具体的要求,否则通常不建议在C++中重载这些运算符.您可以这样做,但它可能会破坏其他人的代码中的预期行为,特别是如果通过实例化类型重载这些运算符的模板间接使用这些运算符.
短路评估和评估顺序是C和C++中的强制语义标准.
如果不是这样,那么这样的代码就不是常见的习语
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规范的逻辑AND运算符(PDF链接)说
(4).与按位二进制和运算符不同,&&运算符保证从左到右的评估; 在评估第一个操作数后有一个序列点.如果第一个操作数比较等于0,则不计算第二个操作数.
同样,6.5.14节Logical OR运算符说
(4)与按位|不同 运算符,|| 运营商保证从左到右的评估; 在评估第一个操作数后有一个序列点.如果第一个操作数比较不等于0,则不计算第二个操作数.
类似的措辞可以在C++标准中找到,请参阅本草案副本中的第5.14节.正如跳棋在另一个答案中指出的那样,如果你重写&&或||,那么必须对两个操作数进行评估,因为它变成了常规函数调用.
是的,它要求(评估顺序和短路).在您的示例中,如果所有函数都返回true,则调用的顺序严格来自functionA,然后是functionB,然后是functionC.用于此类似
if(ptr && ptr->value) { ... }
逗号运算符相同:
// calls a, then b and evaluates to the value returned by b // which is used to initialize c int c = (a(), b());
一个表示的左边和右边的操作数之间&&
,||
,,
和的第一和第二/第三操作数之间?:
(条件运算符)是一个"点序列".在此之前完全评估任何副作用.所以,这是安全的:
int a = 0; int b = (a++, a); // b initialized with 1, and a is 1
请注意,不要将逗号运算符与用于分隔事物的语法逗号混淆:
// order of calls to a and b is unspecified! function(a(), b());
C++标准中说5.14/1
:
&&运算符从左到右分组.操作数都隐式转换为bool类型(第4节).如果两个操作数都为真,则结果为true,否则为false.与&不同,&&保证从左到右的评估:如果第一个操作数为假,则不评估第二个操作数.
并在5.15/1
:
|| 操作员组从左到右.操作数都隐式转换为bool(第4节).如果其任一操作数为true,则返回true,否则返回false.与|,||不同 保证从左到右的评估; 此外,如果第一个操作数的计算结果为true,则不计算第二个操作数.
它说旁边的那些:
结果是布尔.除了临时破坏之外,第一个表达式的所有副作用(12.2)发生在评估第二个表达式之前.
除此之外,1.9/18
说
在评估每个表达式时
a && b
a || b
a ? b : C
a , b
使用这些表达式(5.14,5.15,5.16,5.18)中运算符的内置含义,在评估第一个表达式后有一个序列点.
直接来自古老的K&R:
Ç保证
&&
和||
评估左至右-我们将要看到的情况下,此事项.
要非常非常小心。
对于基本类型,这些是快捷方式运算符。
但是,如果您为自己的类或枚举类型定义这些运算符,则它们不是捷径。由于在不同情况下它们的用法在语义上存在差异,因此建议您不要定义这些运算符。
对于operator &&
和operator ||
类型,评估顺序从左到右(否则,捷径将很难:-),但是对于您定义的重载运算符,它们基本上是定义方法的语法糖,因此参数的评估顺序为未定义。