&& amp;的行为用C编程语言

时间:2013-08-14 10:45:39

标签: c operators logical-operators

我是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

任何人都可以解释一下,为什么我得到这个答案?

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

5 个答案:

答案 0 :(得分:21)

由于Short-circuit evaluation,当x0时,yz并不需要进行评估,因为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;

答案 1 :(得分:14)

我只能考虑&&评估短路:给定A && B,如果A评估false,则{{1} }未被评估。

所以:

B变为X。自0

以来&& ++y && ++z未进行评估 从X/0/false && ...

分配的

y=0

y = x/0/false未经修改,因为z未执行。

答案 2 :(得分:5)

由于第一部分已经确定了++y的新值,因此永远不会评估++zy

你的陈述的第一部分是++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中找到有关序列点的更多信息

答案 3 :(得分:5)

为了完整性(脑转储):

这个巫术背后的术语叫做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

答案 4 :(得分:4)

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

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

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

z因为这是表达式的结果。

{{1}}未被触及