如何在 C 中计算包含递增和递减运算符的逻辑表达式?

How are logical expressions that include increment and decrement operators evaluated in C?

提问人:mizzadnan 提问时间:10/4/2023 最后编辑:mizzadnan 更新时间:10/4/2023 访问量:77

问:

int a = 0, b= 1, c = 1;
if (c-- || ++a && b--)

我知道 && 的优先级在这里是最高的。那么会发生什么呢?它是否从 && 开始,然后查看其左侧的表达式 (c-- || ++a) 并首先计算它?

我已经尝试了一段时间的不同表达方式,但我就是无法理解它。提前致谢。

编辑:如果可以的话,我会使用括号,但这是一个单一的问题,所以我真的没有发言权

c 逻辑运算符 logical-or logical-and

评论

0赞 pmg 10/4/2023
不要试图把你的头缠绕在那些优先级/语法规则上:使用括号==>或...如果从表达式中删除 and,那就更好了。if ((c-- || ++a) && b--)if (c-- || (++a && b--))++--
0赞 mizzadnan 10/4/2023
@pmg是的,但是大学问题并没有真正带有括号,所以..
0赞 Andrew Henle 10/4/2023
更好的是 - 不要把所有这些递增前和递增后的运算符都塞进那一行代码中。该代码将无法通过大多数代码审查,因为它比必要的更复杂,因此无缘无故地更难阅读和维护。
0赞 Barmar 10/4/2023
@AndrewHenle 这是一项家庭作业,他们无法选择风格。
1赞 pmg 10/4/2023
啊!井。。。然后和你的老师谈谈,告诉她看看这个问题:)

答:

4赞 dbush 10/4/2023 #1

运算符优先级并不能完全确定评估顺序。它的作用是指示操作数的分组方式。由于优先级高于您指出的优先级,因此您的表达式等效于:&&||

(c-- || (++a && b--))

鉴于操作者使用短路评估,将在评估之前进行评估。但是,整个子表达式是算子的右侧,该算子也使用短路评估,这意味着左侧,即 将首先接受评估。&&++a++b++a && b--||c--

由于计算结果为 1,因此不计算运算符的右侧,即 。所以被递减,保持不变。c--||++a && b--cab

3赞 Barmar 10/4/2023 #2

由于运算符优先级,这相当于

if (c-- || (++a && b--))

逻辑运算符从左到右处理短路。所以这个首先执行.这递减到 ,但因为它是递减后的,所以该值是它的原始值。这是事实,因此操作员会立即评估到不评估其右手操作数。c--c01||1

所以条件是真的,但只是被修改了。c

0赞 Lundin 10/4/2023 #3

我知道 && 的优先级在这里是最高的。

井。。。不。后缀运算符的优先级最高,次高是前缀 ,然后是 ,然后是 。--++&&||

运算符优先级/关联性仅与确定哪些操作数“粘附”到哪个运算符有关。在这种情况下,运算符优先级使表达式等同于 。(c--) || ((++a) && (b--))

从那时起,我们可以忘记运算符的优先级,而是担心计算的顺序。通常,C 中的运算符不会指定操作数的计算顺序。逻辑 AND 和 OR 在这里是例外,明确说明了定义的计算顺序 (C17 6.5.13):

与按位二进制运算符不同,运算符保证从左到右的计算;如果计算第二个操作数,则在第一个操作数和第二个操作数的计算之间有一个序列点。如果第一个操作数比较等于 0,则不计算第二个操作数。&&&

类似的文本也存在。这些特殊的评估规则通常被称为“短路评估”,这是一个相当无益的类比(详情:“短路”算子是什么意思?||)

所有这些都意味着编译器必须建立一个内部表达式解析器树,其中的子表达式只有在整个表达式得到求值时才会得到求值,而这反过来又取决于 的求值结果。++a && b--(c--)

因此,编译器必须将表达式计算为:

  • 评估,如果结果为 1,则停止评估。然后执行。c--1c--
  • 否则,请评估并执行 .如果 ,则结果为 0,则停止计算。然后执行。++a0c--
  • 否则,请评估 .如果为“1”,则结果为 1,否则为 0。 然后被处决。b--c--b--