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 表达式的计算:
了解运算符优先级和结合律的规则。对于 "simple" 表达式,这些规则几乎可以告诉您有关表达式求值的所有信息。给定 a + b * c
,b
乘以 c
,然后将乘积添加到 a
,因为 *
的优先级高于 +
。给定 a + b + c
,a
与 b
相加,然后将总和与 c
相加,因为 +
从左到右关联。
除了结合性(如第1点所述),尽量不要使用词"left to right"或"right to left"求值。 C 没有从左到右或从右到左的评估。 (显然Java不一样。)
棘手的地方在于副作用。 (当我在第 1 点说“'simple' 表达式”时,我的意思基本上是 "expressions without side effects"。)副作用包括 (a) 函数调用,(b) =
赋值,(c) 赋值使用 +=
、-=
等,当然还有 (d) increments/decrements 使用 ++
和 --
。 (如果从变量中 fetch 很重要,这通常仅适用于限定为 volatile
的变量,我们可以添加 (e) 从 volatile
中获取变量添加到列表中。)一般来说,你无法判断副作用何时发生。尽量不在乎。只要您不关心(只要您的程序对副作用重要的顺序不敏感),就没有关系。但是如果你的程序 是 敏感的,它可能是未定义的。 (更多信息见下文第 4 点和第 5 点。)
您绝不能在试图改变同一个变量的同一个表达式中有两个副作用。 (示例:i = i++
、a++ + a++
。)如果这样做,则表达式未定义。
除了一个 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.
免责声明:我不是这样编码的,我只是想了解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 表达式的计算:
了解运算符优先级和结合律的规则。对于 "simple" 表达式,这些规则几乎可以告诉您有关表达式求值的所有信息。给定
a + b * c
,b
乘以c
,然后将乘积添加到a
,因为*
的优先级高于+
。给定a + b + c
,a
与b
相加,然后将总和与c
相加,因为+
从左到右关联。除了结合性(如第1点所述),尽量不要使用词"left to right"或"right to left"求值。 C 没有从左到右或从右到左的评估。 (显然Java不一样。)
棘手的地方在于副作用。 (当我在第 1 点说“'simple' 表达式”时,我的意思基本上是 "expressions without side effects"。)副作用包括 (a) 函数调用,(b)
=
赋值,(c) 赋值使用+=
、-=
等,当然还有 (d) increments/decrements 使用++
和--
。 (如果从变量中 fetch 很重要,这通常仅适用于限定为volatile
的变量,我们可以添加 (e) 从volatile
中获取变量添加到列表中。)一般来说,你无法判断副作用何时发生。尽量不在乎。只要您不关心(只要您的程序对副作用重要的顺序不敏感),就没有关系。但是如果你的程序 是 敏感的,它可能是未定义的。 (更多信息见下文第 4 点和第 5 点。)您绝不能在试图改变同一个变量的同一个表达式中有两个副作用。 (示例:
i = i++
、a++ + a++
。)如果这样做,则表达式未定义。除了一个 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.