c 中 'postfix decrement' 和 'logical AND' 运算符的运算符关联性

Operator associativity with 'postfix decrement' and 'logical AND' operators in c

免责声明:我不是这样编码的,我只是想了解c语言是如何工作的!!!!

输出为12。

此表达式 (a-- == 10 && a-- == 9) 从左到右求值,a 在 a-- == 10 处仍为 10,但在 a-- == 9 处 a 仍为 9。

1) post-增量求值的时间是否有明确规定?从这个例子来看,它似乎在 && 之前但在 == 之后进行评估。是不是因为&&逻辑运算符让a-- == 10成为一个完整的表达式,所以a执行完后更新了?

2) 同样对于c/c++,某些运算符如前缀递减从右到左出现所以a == --a首先将a递减到9然后比较9 == 9。是否有原因为什么 c/c++ 是这样设计的?我知道 Java,它是相反的(它从左到右求值)。

#include <stdio.h>

int main() {
    int a = 10;
    if (a-- == 10 && a-- == 9)
        printf("1");
    a = 10;
    if (a == --a)
        printf("2");
    return 0;
}

This expression (a-- == 10 && a-- == 9) evaluates left-to-right,

是的,主要是,但只是因为 && 很特别。

and a is still 10 at a-- == 10

是的,因为 a-- 产生旧值。

but a is 9 for a-- == 9.

是的,因为 && 处的序列点保证在评估 RHS 之前完成对 a 值的更新。

1) Is there a clear rule as to when post-increment evaluate?

我认为最好的答案是"no"。由于 ++-- 的副作用在下一个序列点之前的某个时间点完成,但除此之外,您不能说。对于定义明确的表达式,副作用何时完成并不重要。如果一个表达式对副作用何时完成很敏感,那通常意味着该表达式是未定义的。

From this example it seems it evaluates prior to the && but after the ==. Is that because the && logical operator makes a-- == 10 a complete expression, so a is updated after it executes?

基本上是

2) Also for c/c++, certain operators such as prefix decrement occur right to left

小心。我不确定你的意思,但不管它是什么,我几乎可以肯定这不是真的。

so a == --a first decrements a to 9 and then compares 9 == 9.

否,a == --a 未定义。不知道它是做什么的。

Is there a reason for why c/c++ is designed this way?

是的。

I know for Java, it's the opposite (it's evaluates left to right).

是的,Java不一样。


这里有一些指南可以帮助您理解 C 表达式的计算:

  1. 了解运算符优先级和结合律的规则。对于 "simple" 表达式,这些规则几乎可以告诉您有关表达式求值的所有信息。给定 a + b * cb 乘以 c,然后将乘积添加到 a,因为 * 的优先级高于 +。给定 a + b + cab 相加,然后将总和与 c 相加,因为 + 从左到右关联。

  2. 除了结合性(如第1点所述),尽量不要使用词"left to right"或"right to left"求值。 C 没有从左到右或从右到左的评估。 (显然Java不一样。)

  3. 棘手的地方在于副作用。 (当我在第 1 点说“'simple' 表达式”时,我的意思基本上是 "expressions without side effects"。)副作用包括 (a) 函数调用,(b) = 赋值,(c) 赋值使用 +=-= 等,当然还有 (d) increments/decrements 使用 ++--。 (如果从变量中 fetch 很重要,这通常仅适用于限定为 volatile 的变量,我们可以添加 (e) 从 volatile 中获取变量添加到列表中。)一般来说,你无法判断副作用何时发生。尽量不在乎。只要您不关心(只要您的程序对副作用重要的顺序不敏感),就没有关系。但是如果你的程序 敏感的,它可能是未定义的。 (更多信息见下文第 4 点和第 5 点。)

  4. 您绝不能在试图改变同一个变量的同一个表达式中有两个副作用。 (示例:i = i++a++ + a++。)如果这样做,则表达式未定义。

  5. 除了一个 class 例外,您绝不能有试图改变一个变量的副作用,该变量也在同一表达式的其他地方使用。 (示例:a == --a。)如果这样做,则表达式未定义。例外情况是访问的值被用于计算要存储的值,如 i = i + 1.

使用 "logical and" 运算符 (a-- == 10 && a-- == 9) 是格式正确的表达式(没有未定义的行为,因为它在 a++ + a++ 中)。

C 标准关于 "logical and"/"logical or" 运算符的说法:

guarantees left-to-right evaluation; there is a sequence point after the evaluation of the first operand.

因此,第一个子表达式 a-- == 10 的所有副作用在第二个子表达式 a-- == 9 求值之前完成。 a 在计算第二个子表达式之前是 9

逻辑 && 运算符在第一个和第二个操作数的计算之间包含一个 序列点 。部分原因是作为左侧一部分的任何副作用(例如由 -- 运算符执行的副作用)在评估右侧之前已完成。

有关逻辑 AND 运算符的 C standard 的第 6.5.13p4 节对此进行了详细说明:

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.

在这个表达式的情况下:

(a-- == 10 && a-- == 9)

a (10) 的当前值首先与 10 比较是否相等。这是真的,所以右侧被评估,但不是在递减 a 的副作用之前那是在左侧完成的。然后,将 a 的当前值(现在为 9)与 9 进行比较。这也是 true,因此整个表达式的计算结果为 true。在执行下一条语句之前,在右侧完成的递减 a 的副作用已经完成。

然而这个表达式:

if (a == --a)

涉及在同一个表达式中读写a,没有序列点。这会调用 undefined behavior.