政府的行为&;在C语言中

政府的行为&;在C语言中,c,operators,logical-operators,C,Operators,Logical Operators,我是C编程语言的初学者,最近我读了一些关于逻辑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

我是C编程语言的初学者,最近我读了一些关于逻辑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
谁能解释一下,为什么我会得到这个答案

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

发生的事情是,
++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逻辑与运算符部分找到它

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


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

我只能想到
&
短路中求值:给定
a和
,如果
a
求值
false
,则
B
不求值

因此:

X
变为
0
<由于
X/0/false&&&…

y=0
根据
y=x/0/false

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

因为,当
x
0
时,
y
z
实际上不需要计算,因为
0&&ANYTHING
0

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

z
保持不变(
-1



&&
运算符是成对求值的,因此我猜C在求值

((++x && ++y) && ++z)
现在,
++x
将返回零,因此第一个
&&
将失败,第二个
++y
++z
也将失败

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

z
不被触摸

以确保完整性(大脑转储):

这个巫术背后的术语叫做。让我们看一下你的代码,然后简单介绍一下为什么会发生这种情况。看看:

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;
。。。声明三个整数,
x
y
z
。它们在堆栈帧上初始化为垃圾值,因为没有初始化(赋值运算符)。这一行其实并不重要,现在让我们看下一行:

 x = y = z = -1;
。。。我们看到我们在同一条线上做多个作业。回想一下,赋值运算符将对赋值运算符左侧的标识符进行变异(使用赋值运算符右侧的值),并返回
x
的值。这称为赋值重载。但同样,这并不重要——要认识到的唯一重要的事情是
x
y
z
现在都是-1。让我们看下一行:

 y = ++x && ++y && ++z;
 printf( "x = %d, y = %d, z = %d, x, y, z );
。。。尤达说。让我们加上括号,以便更清楚地知道先评估哪个步骤:

 y = ( ( ++x ) && ++y && ++z );
。。。现在看看最里面的括号,我们看到它是一个前缀增量
x
,这意味着我们将增加
x
的值,然后返回它。我们注意到,
x
最初是-1,现在递增后为0。这将解决以下问题:

 y = ( 0 && ++y && ++z );
 y = 0;
。。。现在需要注意的是,看看我们的真值表:

A | B | A && B
--------------
T | T |   T
T | F |   F
F | T |   F
F | F |   F
。。。对于
逻辑运算符,我们看到F(和)T,T(和)F都是F。编译器实现了这一点,并且在计算值为
false的连接(和)时短路,这是一种聪明的优化技术。然后,它将解析为将
y
赋值为0(这是false)。回想一下,在C中,任何非零值都是
true
,只有0是
false
。该行将如下所示:

 y = ( 0 && ++y && ++z );
 y = 0;
。。。现在看下一行:

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

。。。现在对您来说应该很明显,它将输出
x=0,y=0,z=-1

似乎与我闻到的未定义行为非常相似…@devnull我不太确定,但短路评估加增量运算符看起来是获得意外或未定义行为的理想方法。当心鼻魔。@fuzzxl否,
&&
的shot circuit确保此表达式的计算顺序,因此没有未定义的行为。@user2320537赋值不会使此问题唯一。