【问题标题】:Behaviour of && in C programming languageC 编程语言中 && 的行为
【发布时间】:2013-08-16 06:47:39
【问题描述】:

我是C编程语言的初学者,最近我读到了Logical AND &&运算符。

我也知道,在 C 编程语言中,所有非零值都被视为 TRUE

NON-ZERO && NON-ZERO = 1  
NON-ZERO && ZERO = 0  
ZERO && NON-ZERO = 0
ZERO && ZERO = 0  

但是当我处理以下程序时,我没有得到预期的答案。

int main(){  
  int x, y, z;  
  x = y = z = -1;  
  y = ++x && ++y && ++z;  
  printf("x = %d, y = %d, z = %d, x, y, z);  
  return 0;  
} 

期待

x = 0, y = 0, z = 0 

但答案是

x = 0, y = 0, z = -1

谁能解释一下,为什么我会得到这个答案?

编辑: 在这个问题中,我没有询问运算符的优先级。

【问题讨论】:

  • 我闻到了未定义的行为...
  • @devnull 我不太确定,但短路评估加增量运算符看起来像是获得令人惊讶或未定义行为的理想方法。当心鼻恶魔。
  • @FUZxxl 不,&& 的镜头电路确保了这个表达式的计算顺序,所以没有未定义的行为。
  • @user2320537 作业不会使这个问题独特

标签: c operators logical-operators


【解决方案1】:

我只能想到&&短路中进行评估:给定A && B,如果A 评估false,则不评估B

所以:

X 变为 0&& ++y && ++zX/0/false && ... 后不计算

y=0 分配自 y = x/0/false

z 保持不变,因为 ++z 没有被执行。

【讨论】:

    【解决方案2】:

    为了完整性(大脑转储):

    这个巫术背后的术语叫做short circuiting。让我们回顾一下您的代码,然后简要介绍一下为什么会发生这种情况。正在看:

    int main( void ) {  
      int x, y, z;
      x = y = z = -1;
      y = ++x && ++y && ++z;
    
      printf( "x = %d, y = %d, z = %d, x, y, z );
    
      return 0;  
    }
    

    ...我们开始逐行分解它。第一行:

    int x, y, z;
    

    ... 声明三个整数,xyz。它们被初始化为堆栈帧上的垃圾值,因为没有初始化(赋值运算符)。这一行其实无所谓,现在我们看下一行:

     x = y = z = -1;
    

    ...我们看到我们在同一行上执行多个分配。回想一下,赋值运算符将改变赋值运算符左侧的标识符(使用赋值运算符右侧的值)并返回 x 的值。这称为赋值重载。但同样,这并不重要 - 唯一需要意识到的重要事情是 xyz 现在都是 -1。让我们看下一行:

     y = ++x && ++y && ++z;
    

    ...巫术尤达说。让我们添加括号,以便更清楚首先评估哪个步骤:

     y = ( ( ++x ) && ++y && ++z );
    

    ...现在看最里面的括号,我们看到它是x 的前缀增量,这意味着我们将增加x 的值,然后返回它。我们注意到x 最初是-1,增加后现在是0。这将解决如下:

     y = ( 0 && ++y && ++z );
    

    ...现在重要的是要注意查看我们的真值表:

    A | B | A && B
    --------------
    T | T |   T
    T | F |   F
    F | T |   F
    F | F |   F
    

    ... 对于AND 逻辑运算符,我们看到 F (AND) T, T (AND) F 都是 F。编译器在评估连接 (AND) 时会意识到这一点并短路,其中值是false——一种聪明的优化技术。然后它将解析分配y 为0(这是错误的)。回想一下,在 C 中,任何非零值都是 true,只有 0 是 false。该行将如下所示:

     y = 0;
    

    ...现在看下一行:

     printf( "x = %d, y = %d, z = %d, x, y, z );
    

    ...现在你应该很明显它会输出x = 0, y = 0, z = -1

    【讨论】:

      【解决方案3】:

      发生的情况是 ++y++z 永远不会被评估,因为第一部分已经确定了 y 的新值。

      你的语句的第一部分是++x && ...,相当于0 && ...,然后我们已经知道y最后会是0,所以语句的其余部分不会被执行。

      如果你这样做了:

      int main(){  
        int x,y,z,tmp;  
        x = y = z = -1;  
        tmp = ++x && ++y && ++z;  
        printf("x = %d, y = %d, z = %d, tmp = %d", x,y,z, tmp);  
        return 0;  
      } 
      

      你会得到x = 0, y = -1, z = -1, tmp = 0

      左评估在 C99 标准中得到保证。你可以在6.5.13 Logical AND operator部分找到它

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

      您可以在Wikipedia 或 C99 标准的附录 C 中找到有关什么是序列点的更多信息

      【讨论】:

        【解决方案4】:

        && 运算符是成对评估的,因此我猜 C 正在评估

        ((++x && ++y) && ++z)
        

        现在,++x 将返回零,因此第一个 && 将失败,第二个也将失败,而无需评估 ++y++z

        y = 0 因为这是表达式的结果。

        z 没有被触动

        【讨论】:

          【解决方案5】:

          由于Short-circuit evaluation,当x0yz 时,实际上不需要评估,因为0 && ANYTHING0

          一旦x 增加到0,结果就是0,这就是y 得到的。

          z 保持不变 (-1)。


           x  | y  |  z 
          ----+----+-----
           -1 | -1 | -1   //x = y = z = -1;  
            0 | -1 | -1   //++x && ... Now the whole expression is evaluated to 0
            0 |  0 | -1   //y = ++x && ++y && ++z;
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-10-21
            • 2022-06-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-10-06
            相关资源
            最近更新 更多