设e1
和e2
是两个布尔表达式。那么,是否e1 && e2
相当于e2 && e1
在 C 中?
我的直觉告诉我是的。按简单逻辑A & B
等价于B & A
。在 C 中也是如此吗?
从逻辑上讲,是的。 从逻辑的角度来看,e1 && e2
永远不会有不同的结果。e2 && e1
但是从代码的角度来看,如果评估e1
ore2
有副作用,那么不,它们并不完全等价。
具体来说,有时人们会使用.&&
if( isHungry() && hasFood() ) eat() ;
通常,您希望将最便宜的评估条件放在首位,并且仅在第一个条件成立时才检查第二个条件。 短路评估是保证这种情况发生的原因。如果 AND 逻辑运算中的第一个条件是 false,那么甚至不会评估第二个语句,因为最终结果无论如何都不会是 TRUE (FALSE && (TRUE && TRUE && TRUE && TRUE)) == FALSE)
。
换句话说,如果你不饿,你就不会费心去检查冰箱。
有时人们依赖于会发生短路评估这一事实,并编写依赖于它的代码。这种类型的东西显示在下面的评论中:
if( x && x->eval() ) { /* do something */ }
所以,x=NULL
上面说。会发生什么?试图尊重空指针?应该写成
if( x )
{
if( x->eval() )
{
// do something
}
}
我说不!短路评估意味着,如果,则运算符x==0
的正确操作数甚至不会在中查看。 不会被评估,也不会发生空指针异常。&&
if( x && x->eval() )
x->eval()
您必须注意的另一件事是您在 if 语句中运行的函数是否有副作用,例如递增某种计数器。因此,如果hasFood()有一个内部计数器增量,例如fridgeCount++
.
即使在简短的 cct 评估中,该函数甚至都不会运行,因此您在点击 if 语句时预期会发生的任何副作用都可能不会发生。
OR 运算符也有短路求值,仅在 中if( e1 || e2 )
,如果结果为 TRUE,则语句短路为e1
TRUE(然后 e2 甚至不求值,整个表达式被视为TRUE
)。
这种行为适用于 C/C++、Java、JavaScript、PHP、Python 和许多其他语言。
是的,但评价不同。让我指出一个重要的例子。
e1 = (pStruct == NULL)
e2 = (pStruct->value != 0)
e1 && e2
是可以接受的,但是e2 && e1
如果pStruct
是NULL
因为&&
从左到右求值会导致段错误
如果e1
ande2
是没有副作用的表达式并且它们都是独立有效的,那么是的,这将是等价的。
在实践中,即使两个表达式由于短路行为而没有副作用,它们也可能不会产生等效的结果:
// given some array X of 10 members
if (i < 10 && x[i] < 5) {
//... this is not 'equivalent' to:
if (x[i] < 5 && i < 10) {
// ... but obviously:
if (i < 10 && z > 15) {
// ... is equivalent to:
if (z < 15 && i < 10) {
因此,对于任何布尔表达式的一般情况e1
和e2
:不,它们不等价。
对于给定的情况:是的,它们可能在逻辑上是等价的。
是和不是。但是 99%(实际上,可能更多,更多)的时候,是的。
如果你只谈论结果,那么是的。但是,如果您的表达式包含函数或赋值(或任何可以改变某物状态的东西),那么您应该知道 C 很聪明地知道它如何评估 && 的参数。
如果 &&(左值)的第一个表达式为假,则不会计算第二个表达式(右值)。
例如,执行以下操作是安全的:
struct some_struct *x = NULL;
if (x && x->some_struct_value) {
// Some code here
}
由于左值x
被评估为false
,因此通常会使您的应用程序崩溃的右值x->value
不会被评估,您的应用程序也不会崩溃。
另一个例子是这样的:
int always_returns_false() {
return 0;
}
int increment(*int x) {
(*x)++;
return 1;
}
int main() {
int my_int = 0;
if (always_returns_false() && increment(&my_int)) {
// Stuff! (Or no stuff, doesn't matter!)
}
return my_int;
}
如果您在 11 的条件中切换表达式,您可以获得 0 或 1 的返回状态。
因此,尽管在逻辑上(e1 && e2) == (e2 && e1)
,功能上,至少在 C 中,它们可以导致不同的动作和结果。
e1 && e2
e2 && e1
由于短路评估可能不等效,所以如果这些表达式有副作用,这可能会导致不同的行为。逻辑与运算符第4节中的C99 标准草案说:6.5.13
与按位二进制 & 运算符不同,&& 运算符保证从左到右的求值;在计算第一个操作数之后有一个序列点。如果第一个操作数比较等于 0,则不计算第二个操作数。
因此,如果第一个操作数等于 ,则不会计算第二个操作数0
。因此,假设e1
计算结果为0
但e2
计算结果为非零值,那么在这种情况下:
e1 && e2
thene1
将被评估,但e2
不会,但在这种情况下:
e2 && e1
两者都e1
将e2
被评估。