该函数输出的说明
我正在做复习问题,问我“以下是什么输出”,而我在理解这个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
保持不变。
减少a
为0
, b
保持为1
。
正如你的建议,输出为0 1 0
。
关于第二个问题,如果你写c = --a || b++
c = --a || b++
,变量a
再次变为零,但表达式仍然可以评估为真 – 我们必须因此评估第二部分,从而执行返回1
并增加b
b++
。 在这种情况下,输出将为0 2 1
,因为c
被赋值为0 || 1
0 || 1
是1
。
简而言之,请继续阅读
- 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
保持为1
, c
变为0
。
这条线:
c = --a && b++;
将a
减小为0
,因此语句0 && anything else
结果为0
。 这就是为什么a
和c
导致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; 好