使用逻辑运算符和 pre/post 增量未从此代码获得预期输出
Not getting expected output from this code using logical operators and pre/post increment
我在以下 C 代码中没有得到预期的输出
main(){
int i=0,j=-2,k=0,m;
if((!i||--j&&k++)&&(i++||j++&&!k++))
{
printf("i=%d j=%d k=%d",i,j,k);
}
return 0;
}
我在编译器中得到的输出为:
i=1 j=-1 k=1
但我不明白这里到底发生了什么。
我认为 if 语句不应该 运行 因为它的参数是 false
注意第一个括号 (!i||--j&&k++)
此处为 !i=1
因此此括号为真,因为 OR 运算符下带有 1 的任何内容都为真。
输出值变为:i=0, j=-3, k=1
现在注意第二个括号:(i++||j++&&!k++)
这里有( 0 || -3 && !1) = 0, false
由于括号被&&
隔开,if语句的整个参数变为false
.
请解释我的论点哪里错了。我是 C 的新手
您可能错过了 if 语句一旦满足就结束,所以 (!i||--j&&k++)
只会计算 i
而其他操作将被忽略。我的意思是 j
将在第一个语句结束时变为 -2。
让我们稍微展开一下,以便于阅读:
int i = 0, j = -2, k=0, m;
(!i || --j && k++) && (i++ || j++ && !k++)
如您所见,!i
为真(值为 1),因此 ||
为真。如果左操作数为真,则 ||
运算符被定义为不评估其右操作数,因此 --j && k++
不被评估且无效。 (右操作数是 --j && k++
,因为 &&
的优先级高于 ||
,所以 A || B && C
结构为 A || (B && C)
。)
即解决中央&&
的左操作数。在右操作数中,i++
将 i
递增为 1,但计算结果为 i
的当前值 0,因此对于 ||
运算符而言它为假。所以 ||
的右操作数被评估。
那个操作数是j++ && !k++
。由于 j
为 −2,因此 j++
将 j
更改为 −1 并计算为 −2,这是用于 &&
的真值。然后 k++
将 k
递增到 1 但计算结果为 0,并且 !k++
将其更改为 1,对 &&
产生 true,因此对前一个 ||
产生 true和中央 &&
.
此时i
为1,j
为-1,k
为1,就是你得到的结果
逻辑与运算符&&
和逻辑或运算符||
是短路运算符,这意味着如果表达式的结果可以从左侧。
所以当这个子表达式运行时:
(!i||--j&&k++)
解析为:
(!i||(--j&&k++))
||
的左侧计算结果为真,因此 --j&&k++
未计算,这意味着 j
的值保持为 -2,k
的值保持不变保持为 0.
所以最外层的左边&&
为真,所以现在我们计算右边:
(i++||j++&&!k++)
解析为:
(i++||(j++&&!k++))
i
递增为 1,然后在 ||
中使用旧值。旧值 0 的计算结果为 false,因此计算右侧。 j
递增到 -1 并且 -2 的旧值评估为 true,因此评估 &&
的右侧。 k
递增到 1,旧值 0 应用于计算结果为 true 的 !
运算符。这使得整个表达式为真并打印语句,此时i
为1,j
为-1,k
为1。
我在以下 C 代码中没有得到预期的输出
main(){
int i=0,j=-2,k=0,m;
if((!i||--j&&k++)&&(i++||j++&&!k++))
{
printf("i=%d j=%d k=%d",i,j,k);
}
return 0;
}
我在编译器中得到的输出为:
i=1 j=-1 k=1
但我不明白这里到底发生了什么。
我认为 if 语句不应该 运行 因为它的参数是 false
注意第一个括号 (!i||--j&&k++)
此处为 !i=1
因此此括号为真,因为 OR 运算符下带有 1 的任何内容都为真。
输出值变为:i=0, j=-3, k=1
现在注意第二个括号:(i++||j++&&!k++)
这里有( 0 || -3 && !1) = 0, false
由于括号被&&
隔开,if语句的整个参数变为false
.
请解释我的论点哪里错了。我是 C 的新手
您可能错过了 if 语句一旦满足就结束,所以 (!i||--j&&k++)
只会计算 i
而其他操作将被忽略。我的意思是 j
将在第一个语句结束时变为 -2。
让我们稍微展开一下,以便于阅读:
int i = 0, j = -2, k=0, m;
(!i || --j && k++) && (i++ || j++ && !k++)
如您所见,!i
为真(值为 1),因此 ||
为真。如果左操作数为真,则 ||
运算符被定义为不评估其右操作数,因此 --j && k++
不被评估且无效。 (右操作数是 --j && k++
,因为 &&
的优先级高于 ||
,所以 A || B && C
结构为 A || (B && C)
。)
即解决中央&&
的左操作数。在右操作数中,i++
将 i
递增为 1,但计算结果为 i
的当前值 0,因此对于 ||
运算符而言它为假。所以 ||
的右操作数被评估。
那个操作数是j++ && !k++
。由于 j
为 −2,因此 j++
将 j
更改为 −1 并计算为 −2,这是用于 &&
的真值。然后 k++
将 k
递增到 1 但计算结果为 0,并且 !k++
将其更改为 1,对 &&
产生 true,因此对前一个 ||
产生 true和中央 &&
.
此时i
为1,j
为-1,k
为1,就是你得到的结果
逻辑与运算符&&
和逻辑或运算符||
是短路运算符,这意味着如果表达式的结果可以从左侧。
所以当这个子表达式运行时:
(!i||--j&&k++)
解析为:
(!i||(--j&&k++))
||
的左侧计算结果为真,因此 --j&&k++
未计算,这意味着 j
的值保持为 -2,k
的值保持不变保持为 0.
所以最外层的左边&&
为真,所以现在我们计算右边:
(i++||j++&&!k++)
解析为:
(i++||(j++&&!k++))
i
递增为 1,然后在 ||
中使用旧值。旧值 0 的计算结果为 false,因此计算右侧。 j
递增到 -1 并且 -2 的旧值评估为 true,因此评估 &&
的右侧。 k
递增到 1,旧值 0 应用于计算结果为 true 的 !
运算符。这使得整个表达式为真并打印语句,此时i
为1,j
为-1,k
为1。