我最近遇到了一些我认为我立即理解的东西,但是在思考它之后,我想了解它为什么会像它一样工作。
请考虑以下代码。 (x-- == 9)
显然正在评估,而(y++ == 11)
则没有。我的第一个想法是逻辑&&
开始,看到表达式已经变为假,并在评估表达式的第二部分之前启动。
我越是想到它,我就越不明白为什么会这样做。据我了解,逻辑运算符按优先级顺序低于增量运算。即使整体表达式已经变为假,也不应该(y++ == 11)
进行评估吗?
换句话说,操作顺序是否应该在(y++ == 11)
语句实现整个表达式之前判断if
是否会被评估?
#include <iostream>
using namespace std;
int main( int argc, char** argv )
{
int x = 10;
int y = 10;
if( (x-- == 9) && (y++ == 11) )
{
cout << "I better not get here!" << endl;
}
cout << "Final X: " << x << endl;
cout << "Final Y: " << y << endl;
return 0;
}
输出:
Final X: 9
Final Y: 10
答案 0 :(得分:49)
逻辑运算符按顺序低于增量运算 优先级。
优先顺序是不执行顺序。他们是完全不同的概念。优先顺序仅影响在操作符之前评估操作数的执行顺序,优先顺序有助于告诉您每个操作符的操作数。
短路运算符是一个部分例外甚至是操作符在操作符之前进行评估的规则,因为它们评估LHS,然后运算符说明是否评估RHS, may 评估RHS,然后计算运算符的结果。
不要认为高优先级操作“先执行”。想想他们“更紧密”。 ++
的优先级高于&&
,而在x ++ && y ++
表达式中,运算符优先级意味着++
与y
的绑定比&&
更紧密。 }},所以表达式总体上等同于(x++) && (y++)
,而不是(x++ && y) ++
。
答案 1 :(得分:45)
即使整体表达式已成为
(y++ == 11)
,也不应对false
进行评估吗?
否:&&
和||
运算符短路:它们从左到右进行评估,一旦表达式的结果已知,评估就会停止(即尽快因为在一系列false
的情况下,已知表达式为&&
,或在一系列true
(*)的情况下为||
做一些不需要做的额外工作是没有意义的。这种短路行为也非常有用,可以编写高级代码。例如,给定指向struct-type对象的指针,您可以测试指针是否为null,然后在后续子表达式中取消引用指针,例如:if (p && p->is_set) { /* ... */ }
。
(*)请注意,在C ++中,您可以为类型操作数重载&&
和||
,如果这样做,它们会丢失其短路属性(通常是不可取的)因此导致&&
和||
重载。)
答案 2 :(得分:13)
优先级和关联性 not 指定实际执行操作的顺序。它们指定操作的分组方式:即,在以下表达式中:
x && y++
... &&
的较低优先级表示它被分组为好像是:
x && (y++)
而不是
(x && y)++
在您的表达式中,&&
和++
的相对优先级无关紧要,因为无论如何您已将这些运算符与括号分开。
分组(以及优先级和关联性)指定每个运算符正在运行的值;但它时没有指定。
对于大多数运算符,未指定执行运算的顺序 - 但是,在&&
的情况下,指定首先计算左侧操作数,然后仅计算右侧操作数的结果左手操作数的值为非零。
答案 3 :(得分:7)
没有。优先顺序只是决定你是否得到这个:
A && B
(A
为x-- == 9
且B
为y++ == 11
)或
A == B == C
(A
为x--
,B
为9 && y++
,C
为11)。
显然,我们正在处理第一个案件。短路完全适用;如果A
为真,则不评估B
。
答案 4 :(得分:1)
条件运算符从左到右进行求值,并在结果已知时立即停止(带有错误的AND或带有真值的OR)。
答案 5 :(得分:-2)
C标准没有规定if中任何特定的表达式评估顺序。所以行为将是编译器特定的,并且使用这种编码风格不可移植。你面临这个问题,因为值的递增/递减是后期操作,但标准表示作为使用变量的表达式的后期操作。因此,如果编译器认为您的表达式只是单个变量用法为x或y,那么您将看到一个结果。如果编译器认为表达式是完整的表达式评估,那么您将看到其他结果。我希望它有所帮助。