使用逻辑运算符和前后递增未从此代码获得预期的输出

Abh*_*hay -1 c logical-operators pre-increment 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;
}
Run Code Online (Sandbox Code Playgroud)

我在编译器中得到的输出为:

i=1 j=-1 k=1
Run Code Online (Sandbox Code Playgroud)

但是我不明白这里到底发生了什么。

我认为if语句不应运行,因为其参数为false

注意第一个括号 (!i||--j&&k++)

因为!i=1括号中的任何一个在OR运算符下均为1 ,所以此括号为true。

输出值变为: i=0, j=-3, k=1

现在注意第二个括号: (i++||j++&&!k++)

这边有 ( 0 || -3 && !1) = 0, false

当方括号被分隔时&&,if语句的整个参数变为false

请向我解释我的论点错了。我是C的新手

dbu*_*ush 6

逻辑AND运算符&&和逻辑OR运算符||是短路运算符,这意味着如果可以从左侧确定表达式的结果,则不会评估右侧。

因此,当此子表达式运行时:

(!i||--j&&k++) 
Run Code Online (Sandbox Code Playgroud)

解析为:

(!i||(--j&&k++)) 
Run Code Online (Sandbox Code Playgroud)

||评估的左侧为true,因此--j&&k++不进行评估,这意味着keeps的值j是-2,而k剩余的值是0。

所以最外面的左边&&是正确的,所以现在我们评估右边:

(i++||j++&&!k++)
Run Code Online (Sandbox Code Playgroud)

解析为:

(i++||(j++&&!k++))
Run Code Online (Sandbox Code Playgroud)

i增加到1,然后在中使用旧值||。旧值0评估为false,因此评估右侧。 j递增到-1,旧值-2评估为true,因此&&评估右侧。 k会增加到1,并将旧值0应用于!计算结果为true 的运算符。这使整个表达式为真,并打印语句,此时的i值为1,j-1和k1。


Eri*_*hil 5

让我们稍微扩展一下,使阅读更轻松:

int i = 0, j = -2, k=0, m;

(!i || --j && k++) && (i++ || j++ && !k++)
Run Code Online (Sandbox Code Playgroud)

如您所知,它!i为true(值1),因此||为true。该||运营商是指如果左操作数是真的不评价其右操作数,所以--j && k++不评价,并没有任何影响。(正确的操作数是--j && k++因为&&优先级高于||,因此A || B && C结构为A || (B && C)。)

这解决了中央的左操作数&&。在右侧的操作数中,i++递增i为1,但求值为当前值i0,因此对于||运算符而言,它为false 。因此,||将评估该操作数的正确操作数。

该操作数为j++ && !k++。由于j是?2,因此j++更改j为?1并求值为?2,对于而言,该值为true &&。然后k++增量k1,但计算结果为0,并!k++改变它为1,产生用于真&&,并因此为先前真||和中央&&

此时,i1 j是?1,并且k是1,这就是您得到的结果。