C &&;和| |运算符

C &&;和| |运算符,c,operators,boolean,C,Operators,Boolean,我遇到了以下代码: int main() { int i=1,j=2,k=0,m=0; m = ++i || ++j && ++k; printf("%d %d %d %d %d",i,j,k,m); } 程序返回2 2 0 1…。为什么? &的优先级高于|,因此应首先计算++j&&++k。因此,我希望j=3和k=1。它将返回true,因此|变为true,因此不应计算++i。但它的工作方式正好相反 我希望其

我遇到了以下代码:

    int main()
    {
        int i=1,j=2,k=0,m=0;
        m = ++i || ++j && ++k;
        printf("%d %d %d %d %d",i,j,k,m);
    }
程序返回
2 2 0 1…
。为什么?

&
的优先级高于
|
,因此应首先计算
++j&&++k
。因此,我希望
j=3
k=1
。它将返回true,因此
|
变为true,因此不应计算
++i
。但它的工作方式正好相反


我希望其他人向我解释。

实际上,
++I
将首先进行评估。只有当它为false时,才会对右侧进行评估(在您的情况下不是)

“&&具有更高优先级”这一事实与优先级(其操作数与优先级的关系有多紧密)有关,而不是与“谁的操作数首先得到求值”有关

由于
&&
确实位于表中的
|
上方,因此表达式的解释如下:

m = ++i || (++j && ++k)
因为| |和&&因此指定


注意:这最初是用C++来标记的,在那里你得到了一个稍微不同的答案,比如重载操作符“或”&“不短路,只是内置的< /P> < P>基本上,<代码> < <代码>”意思是,“如果你收到了一些真实的东西,返回它,否则,返回任何发生的事情。”这里唯一要计算的是

m=(++i!=0)
。这意味着“增量i,将m分配给i的值,而不是0,break。”

更具体地说,这就是正在发生的事情:

i = 1;
i = i + 1;
if( i ) {
   m = 1;
}
else { // who cares, this will never happen.
   j = j + 1;
   if( j ) {
       k = k + 1;
       m = (k != 0); // 1
   }
   else {
       m = 0;
   }
}

具有更高的优先级并不意味着首先对其求值。它只是意味着它结合得更紧。在该示例中,该表达式等效于:
++i | |(++j&&++k)
。首先计算的是
++i
,因为
|
从左到右计算。只有当计算结果为false时,才会计算
++j&&++k
,因为
|
短路。

。如果
&&
的左侧为非零,则仅对右侧进行求值。同样,只有当
|
的左侧为零时,才会计算右侧。

快捷方式运算符将导致不必要的表达式组件不被计算。由于&&具有更高的优先级,如果希望在++i的计算结果为true时允许| |运算符缩短整个表达式,则需要最后计算它。由于是这种情况,++i是唯一一个在“=”之后计算的变量。

“更高的运算符优先级”与“先计算”不同。使用短路运算符时,将从左到右对其求值。任何算法的结果都会受到运算符优先级的影响,但这不会改变短路的左-右顺序


您的示例的复杂性是不做这类事情的一个很好的理由。即使你弄明白了规则并确切地知道它会做什么,下一个来查看代码的程序员也可能不会。你在这里看到的是逻辑运算符短路。如果
|
条件的第一部分为true,则它永远不会计算表达式的其余部分(因为如果第一部分是指针非null检查,则如果第二部分为null,则不希望取消对该指针的引用)。此外,由于它是布尔结果表达式,
++i
的结果在分配到
m
之前被转换回
bool
1


避免像瘟疫一样使用此类代码,它只会在短期和长期给您带来调试噩梦。

优先级和求值顺序是两码事。
|
&&
都从左到右计算其操作数;优先权不会改变这一点


给定表达式
a | b&c
a
将首先求值。如果结果为0,则将计算
b和&c

比较运算符(| |和&&)的顺序更为重要。
这就是为什么您最好将最重要的测试放在第一位。

在C语言中,有两个不同的问题需要注意:运算符优先级和求值顺序

运算符优先级确定首先计算其操作数的运算符,以及属于哪个运算符的操作数。例如,在表达式
a+b*c
中,运算符*的运算符优先级高于+。因此,表达式的计算结果为

a+(b*c)

C语言中的所有运算符都具有确定性优先级,并且它们在任何编译器上都是相同的

求值顺序决定首先求值的操作数。请注意,子表达式也是操作数。在确定运算符优先级后应用求值顺序。如果上面的a+b*c示例具有从左到右的求值顺序,则操作数本身将按照a、b、c的顺序求值。如果操作数是例如函数调用,那么函数a()、b()和c()将按该顺序执行。本例中的所有操作数都需要求值,因为它们都已使用。如果编译器可以确定某些操作数不需要求值,则可以对其进行优化,而不管这些操作数是否包含副作用(如函数调用)

问题是,操作数的求值顺序通常是未指定的行为,这意味着编译器可以自由地从左到右或从右到左求值,我们无法知道或假设任何有关它的情况。这对于C语言中的大多数操作数都是正确的,只有少数例外情况下求值顺序始终是确定的。这些是运算符
|&&&&?:,
的操作数,其中计算顺序保证从左到右。(当使用正式的C语言语义时,可以说在左操作符和右操作符的求值之间有一个序列点。)


因此,对于特定示例
m=+