main()
{
int k = 5;
if(++k <5 && k++/5 || ++k<=8); // how to compiler compile this statement
print f("%d",k);
}
// 这里的答案是 7,但为什么?
main()
{
int k = 5;
if(++k <5 && k++/5 || ++k<=8); // how to compiler compile this statement
print f("%d",k);
}
// 这里的答案是 7,但为什么?
++k < 5
计算结果为假(6 < 5 = 假),因此&&
不计算运算符的 RHS(因为已知结果为假)。++k <= 8
然后计算 (7 <= 8 = true),因此完整表达式的结果为 true,并且k
已递增两次,使其最终值为 7。
请注意,&&
and||
是短路布尔运算符 - 如果表达式的结果可以由左侧参数确定,则不计算右侧参数。
另请注意,与大多数运算符不同,短路运算符在表达式中定义序列点,这使得在上面的示例k
中在同一表达式中多次修改是合法的(通常,如果没有干预序列点,这是不允许的,并导致Undefined行为)。
与许多这样的问题不同,在我看来,您的代码实际上已经定义了行为。
两者&&
并||
施加序列点。更具体地说,他们首先评估他们的左操作数。然后有一个序列点1。然后(当且仅当有必要确定结果时)他们评估他们的正确操作数。
可能还值得一提的是,由于 and 的相对优先级&&
,||
表达式:if(++k <5 && k++/5 || ++k<=8)
等效于: if((++k <5 && k++/5) || ++k<=8)
。
所以,让我们一步一步来:
int k = 5;
if(++k <5 &&
所以,首先它评估了这么多。这增加k
了 ,因此它的值变为 6。然后比较它是否小于 5,这显然会产生错误。
k++/5
由于先前的结果是,因此不会评估false
此操作数(因为仍然始终产生结果)。false && <anything>
false
|| ++k<=8);
所以,当执行到这里时,它有false || <something>
. 由于false | x
is的结果x
,它需要评估正确的操作数以获得正确的结果。因此,它++k
再次计算,因此k
递增到 7。然后将结果与 8 进行比较,并发现(显然)7 小于或等于 8——因此if
,执行null 语句,它什么也不做)。
所以,在if
语句之后,k
已经增加了两次,所以它是7
.
在以下:
当第一个条件为&&
真时评估“某事”
||
当第一个条件为 False 时评估“某事”
( (++k <5) && (k++/5) ) || (++k<=8)
( 6 < 5 AND something ) OR something
( False AND something ) OR something
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
False OR 7 < 8
False OR True
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
True
所以k
结果是7
最初在您的声明k
中分配5
,然后在以下 if 条件中:
++k < 5 && k++ / 5 || ++k <= 8
// ^
// evaluates
递增k
到 6,然后其和&&
操作数的 LHS 评估为假。
6 < 5 && k++ / 5 || ++k <= 8
// ^ ^^^^^^^
// 0 not evaluates
然后由于 && 运算符的短路行为k++ / 5
将不会评估。
&& 运算符的短路行为是:
0 && any_expression == 0
,因此any_expression
不需要评估。
所以上面第2步的条件表达式就变成了:
0 || ++k <= 8
// ^^^^^^^^
// evaluates
增加到k
7 然后它的:
0 || 7 <= 8
因为你有;
after if
,所以无论 if 条件将评估 True 还是 Falseprintf()
都会被调用k = 7
。