2

e1e2是两个布尔表达式。那么,是否e1 && e2相当于e2 && e1在 C 中?

我的直觉告诉我是的。按简单逻辑A & B等价于B & A。在 C 中也是如此吗?

4

5 回答 5

14

从逻辑上讲,是的。 从逻辑的角度来看,e1 && e2永远不会有不同的结果。e2 && e1

但是从代码的角度来看,如果评估e1ore2有副作用,那么,它们并不完全等价。

具体来说,有时人们会使用.&&

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,则语句短路为e1TRUE(然后 e2 甚至不求值,整个表达式被视为TRUE)。

这种行为适用于 C/C++、Java、JavaScript、PHP、Python 和许多其他语言。

于 2013-09-12T19:23:01.973 回答
2

是的,但评价不同。让我指出一个重要的例子。

e1 = (pStruct == NULL)
e2 = (pStruct->value != 0)

e1 && e2是可以接受的,但是e2 && e1如果pStructNULL因为&&从左到右求值会导致段错误

于 2013-09-12T19:25:15.800 回答
0

如果e1ande2是没有副作用的表达式并且它们都是独立有效的,那么是的,这将是等价的。

在实践中,即使两个表达式由于短路行为而没有副作用,它们也可能不会产生等效的结果:

// 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) {

因此,对于任何布尔表达式的一般情况e1e2:不,它们不等价

对于给定的情况:是的,它们可能在逻辑上是等价的。

于 2013-09-12T19:25:11.270 回答
0

是和不是。但是 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 中,它们可以导致不同的动作和结果。

于 2013-09-12T19:40:16.093 回答
0

e1 && e2e2 && e1由于短路评估可能不等效,所以如果这些表达式有副作用,这可能会导致不同的行为。逻辑与运算符4节中的C99 标准草案说:6.5.13

与按位二进制 & 运算符不同,&& 运算符保证从左到右的求值;在计算第一个操作数之后有一个序列点。如果第一个操作数比较等于 0,则不计算第二个操作数

因此,如果第一个操作数等于 ,则不会计算第二个操作数0。因此,假设e1计算结果为0e2计算结果为非零值,那么在这种情况下:

e1 && e2

thene1将被评估,但e2不会,但在这种情况下:

e2 && e1

两者都e1e2被评估。

于 2013-09-12T19:44:42.610 回答