如何计算 C 中运算符优先级 table 的表达式?

How to tally the expression with operator precedence table in C?

我知道下面的代码不是用 C 编写表达式的好方法,可能有很多 post 已经劝阻这样的 post,但我确信输出不是编译器依赖。

代码如下所示:

#include <stdio.h>

int main() {
    int x = 2;
    int y = 1;
    int z = x || ++y;
    
    printf("%d %d %d\n", x, y, z);
    return 0;
}

我有以下问题:

  1. 现在我知道短路会发生并且 ++y 永远不会被评估但是如果我没记错的话,一元运算符的优先级高于逻辑运算符因此 ++y 应该先发生,表达式应该从反向短路,对吗?

  2. 还有一个问题是,如果短路从左侧开始发生,那么x首先被评估,然后因为短路,x的值应该被分配给 z,但得到的答案是 1。为什么这样?

关于 Cppreference 的 order of evaluation 文章在这里是一个有用的资源。

问题 1

运算符结合性求值顺序之间存在差异。前者指定如何解析(子)表达式,或者换句话说“将括号放在哪里”。后者处理是否以及以什么顺序评估子表达式。

引用Cppreference上给出的例子:

[..] the expression f1() + f2() + f3() is parsed as (f1() + f2()) + f3() due to left-to-right associativity of operator+, but the function call to f3 may be evaluated first, last, or between f1() or f2() at run time.

关于评估顺序有几条规则。这里的一个重要概念是序列点:

If a sequence point is present between the subexpressions E1 and E2, then both value computation and side effects of E1 are sequenced-before every value computation and side effect of E2.

由于使用了逻辑或运算符,语句 int z = x || ++y; 包含一个序列点:

  1. There is a sequence point after evaluation of the first (left) operand and before evaluation of the second (right) operand of the following binary operators: && (logical AND), || (logical OR), and , (comma).

结合两个引用,这意味着 x 将首先被评估。由于 x 不为零,因此不计算 OR 表达式的右侧,逻辑或运算符的结果为 1(请参阅 here)。这也意味着 ++y 的副作用 不会 发生。

此行为是根据 C 标准定义的,因此 编译器相关(即未 实现定义 )。

问题 2

这里的逻辑或运算符 而不是 结果是 x ,因为它代表一个布尔值。在 C 中,对于所有布尔表达式,int 类型 1 表示真表达式,int 类型 0 表示假表达式。

输出

代码将为 x y z 打印 2 1 1,因为 xy 自初始化以来未更改,逻辑或运算符导致 1.