C 运算符和优先级

C Operators and Precedence

我用的是C语言,代码如下:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int num1=0;

    int res = ++num1 && num1++;

    printf("%d\t%d\n",num1,res);    
}

在上面的代码中,我得到的输出是 2 1。我认为输出应该是 2 0.

如有错误请指正,为了解决这个问题,num1++(0)优先级最高,然后执行++num1(2),最后执行&&,因为它具有最低的优先级。

请评论此语句是如何执行的。

在一些教程中,我发现后缀 ++ 和前缀 ++ 具有相同的优先级,但如果这是真的,那么根据关联性规则,num1++ 应该首先执行(从右到左),这应该再次执行导致回答为 2 0.

在用作初始值设定项的表达式中

 int res = ++num1 && num1++;

运算符&&有一个序列点。

来自 C 标准(6.5.13 逻辑与运算符)

3 The && operator shall yield 1 if both of its operands compare unequal to 0; otherwise, it yields 0. The result has type int.

4 Unlike the bitwise binary & operator, the && operator guarantees left-to-right evaluation; if the second operand is evaluated, there is a sequence point between the evaluations of the first and second operands. If the first operand compares equal to 0, the second operand is not evaluated.

首先计算运算符的左操作数,结果 num1 由于一元(前缀)增量运算符而等于 1。由于子表达式不等于 0,因此计算第二个操作数。它的值是递增之前的值,即 1。由于此第二个操作数也不等于 0,因此整个表达式的计算结果为逻辑真,其值为 1(请参阅 C 标准中的第一条引述)。

这个值1被赋值给变量res,而后缀增量后的变量num1将等于2。

所以在这个声明之后你会得到 res 等于 1 并且 num1 等于 2.

这里有很多误解。首先,运算符优先级表示解析的顺序,而不是执行的顺序。有两个相关但不同的术语,运算符优先级和求值顺序。
参见 What is the difference between operator precedence and order of evaluation?

一旦您理解了求值顺序,&& 运算符就会特别附带明确定义的顺序,而 C 运算符通常不会出现这种情况。它保证了从左到右的评估顺序。 C17 6.5.14/4:

Unlike the bitwise | operator, the || operator guarantees left-to-right evaluation; if the second operand is evaluated, there is a sequence point between the evaluations of the first and second operands. If the first operand compares unequal to 0, the second operand is not evaluated.

通常情况下,您无法将 ++ 运算符与其他运算符混合使用,但上述 && 规则在这种特定情况下使其成为可能。

参见 Why can't we mix increment operators like i++ with other operators? 它解释了 sequencing/sequence 点。


In some of the tutorials I find that postfix ++ and prefix ++ have the same precedence,

他们没有,前缀 ++ 优先于后缀(和其他一元运算符)。所以结合律不适用。

Please correct me if wrong, to solve this statement, the num1++(0) would be executed first due to highest precedence and then ++num1(2) would be executed and then at last && will be preformed because it has the lowest precedence.

优先级仅控制哪些运算符与哪些操作数分组 - 它不影响表达式的计算顺序。

&&||?: 和逗号运算符都强制从左到右求值 - 左操作数在之前被完全求值(并应用任何副作用)正确的操作数。 &&|| 短路 - 对于 &&,仅当左操作数不为零时才计算右操作数。

一元(前缀)++ 运算符生成操作数的当前值加 1,因此 ++num1 的结果是 1。作为 副作用 num1 中的值会增加。由于此结果不为零,因此也会计算 num1++。后缀 ++ 运算符产生操作数的当前值,因此 num1++ 的结果是 1。作为副作用,num1 中的值会增加。

如果两个操作数都不为零,&& 表达式的结果为 1,否则为 0

大致相当于写作

tmp = num1 + 1;
num1 = num1 + 1;

res = 0;
if ( tmp != 0 )
{
  if ( num1 != 0 )
  {
    res = 1;
  }
}
num1 = num1 + 1;

所以++num1 && num1++结果1,最后num1中存储的值为2.

In some of the tutorials I find that postfix ++ and prefix ++ have the same precedence,

那是非常错误的,您应该立即停止使用这些教程。后缀运算符的优先级高于一元运算符 - *a++ 被解析为 *(a++)++a[i] 被解析为 ++(a[i]),等等。像 ++i++ 这样的表达式将被解析如 ++(i++),但你不能在 C 中编写这样的表达式 - i++ 的结果不是 lvalue 并且不能是一元操作数++ 那样。