该函数输出的说明

我正在做复习问题,问我“以下是什么输出”,而我在理解这个function方面遇到了一些麻烦:

int a = 1, b = 1, c = -1; c = --a && b++; printf("%d %d %d", a, b, c); 

输出是010.我的问题是关于第2行, c = --a && b++ 。 如何处理此行,以及它如何工作/更改值? 如果它是c = --a || b++ c = --a || b++ ? 从我的理解,我认为输出将是020。

理解结果的关键概念是布尔运算符( &&|| ) 的短路评估 – 如果在评估布尔运算符的左侧之后,右侧的值不会影响整体结果 ,那么它将不会被评估,它将产生的任何副作用都不会发生

在第一种情况下,由于--a计算为0 (= false),因此不评估... && ...的第二部分,因为“ false AND anything ”将始终为false。 具体来说, b++永远不会被执行,因此它的值在输出中保持为1

--a || b++的情况下 --a || b++ ,整个表达式的值不能由左侧确定(“ false OR something ”仍然可以为true)所以b++ 评估(并且它是副作用,递增b ,发生)。

完全理解结果所需的另一个概念是前后增量/减量运算符之间的差异。 如果--++出现变量之前 (如在--a ),则变量首先递减或递增, 值用于计算整个表达式。 如果--++出现变量之后(如在b++ ),则变量的当前值用于计算表达式,并且在此之后发生增量/减量。

应该注意的是,试图组合同一个变量的两个或多个-- / ++实例(例如a++ + ++a )的表达式很可能会调用未定义的行为 – 结果可能因平台,编译器而异。编译器甚至是一天中的时间。

在表达式c = --a && b++a减少并返回。 现在表达式--a && b++的第二个参数由于短路评估而没有被评估 – 一旦我们看到--a==0我们已经知道表达式将为0 而不管另一个参数是什么 – – ,所以b保持不变。

减少a0b保持为1

正如你的建议,输出为0 1 0

关于第二个问题,如果你写c = --a || b++ c = --a || b++ ,变量a再次变为零,但表达式仍然可以评估为真 – 我们必须因此评估第二部分,从而执行返回1并增加b b++ 。 在这种情况下,输出将为0 2 1 ,因为c被赋值为0 || 1 0 || 11

简而言之,请继续阅读

  • C和C ++之前和之后的增量
  • 短路评估 。

首先需要关注的是前缀和后缀运算符的属性及其差异。

  • 对于Postfix递增和递减运算符, C11 ,章节§6.5.2.4,( 强调我的

    postfix ++运算符的结果是操作数的值 。 作为副作用,操作数对象的值递增[…]后缀--运算符类似于后缀++运算符,除了操作数的值递减。

  • 对于前缀增量和减量运算符, C11 ,章节§6.5.3.1,( 强调我的

    前缀++运算符的操作数的值递增。 结果是增量后操作数的新值。 […]前缀--运算符类似于前缀++运算符,除了操作数的值递减。

现在,出现了Logical AND( && )运算符的属性。 从章节§6.5.13,( 再次强调我的

&&运算符保证从左到右的评估; 如果评估第二个操作数,则在第一个和第二个操作数的评估之间存在一个序列点。 如果第一个操作数比较等于0,则不计算第二个操作数。 […]

所以,在你的情况下,

 int a = 1, b = 1, c = -1; c = --a && b++; 

被评估为

 c = 0 && .....; // done..., a is decremented to 0, // so, LHS of && is 0, RHS is not evaluated, // b remains 1 // and finally, C gets 0. 

另一方面,如果使用逻辑OR( || ),那么,根据属性,在章节§6.5.14中提到

[…] || 运营商保证从左到右的评估; 如果评估第二个操作数,则在第一个和第二个操作数的评估之间存在一个序列点。 如果第一个操作数比较不等于0,则不计算第二个操作数。

所以,对于这种情况

 int a = 1, b = 1, c = -1; c = --a || b++; 

它将被评估为

 c = 0 || 1; //yes, b's value will be used, and then incremented. 

所以,

 printf("%d %d %d", a, b, c); 

将会

 0 2 1 

b ++根本就不会被执行,因为 – 在一个和条件中评估为false。 由于不需要,它的右侧永远不会被执行。 因此b永远不会增加,因此你没有预料到的输出。

 c = --a && b++; 

在第一个–a是evaulated而a变为0 ,只要&& 1个操作数为假, b++不被评估,因此, b保持为1c变为0

这条线:

 c = --a && b++; 

a减小为0 ,因此语句0 && anything else结果为0 。 这就是为什么ac导致0 ,因为你似乎已经理解了。

现在让我们看看你没有得到的部分。 当a被评估为0&&的右边部分不需要被评估,因为无论计算出右边部分的值是什么,结果都将为0 。 这意味着不会评估b++ ,因此b将保留其初始值。 这就是为什么你看到值1而不是2 ,因此输出0 1 0而不是0 2 0

–a:意思是你在行前减少a。 b ++:执行该行后增加b。 这样c(那个时候)= 0 + 1 = 1; 那么:a = 0,b = 2,c = 1; 好