c中具有“后缀减量”和“逻辑与”运算符的运算符关联

时间:2018-10-10 19:46:11

标签: c operator-precedence post-increment side-effects sequence-points

免责声明:我不是这样的代码,我只是想了解c语言的工作原理!!!!

输出为12。

此表达式(a-- == 10 && a-- == 9)从左到右求值,并且a-- == 10的a仍为10,而a-- == 9的a为9。

1)关于增加后评估的时间是否有明确的规定?从此示例看来,它在&&之前但在==之后进行求值。那是因为&&逻辑运算符使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;
}

3 个答案:

答案 0 :(得分:1)

  

此表达式(a-- == 10 && a-- == 9)从左到右求值,

是的,主要是因为&&很特殊。

  

a在a--仍为10时= 10

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

  

但是a-- = 9时a为9。

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

  

1)关于增加后评估的时间有明确的规定吗?

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

  

在此示例中,它似乎在&&之前但在==之后求值。那是因为&&逻辑运算符使a-- == 10是一个完整的表达式,所以a在执行后会更新吗?

基本上是。

  

2)同样对于c / c ++,某些运算符(如前缀递减)从右到左出现

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

  

所以a ==-首先将a减至9,然后比较9 == 9。

否,a == --a未定义。没有告诉它做什么。

  

为什么以这种方式设计c / c ++?

是的

  

对于Java,我知道这是相反的(它从左到右求值)。

是的,Java不同。


以下一些指南可帮助您了解C表达式的评估:

  1. 了解运算符优先级和关联性的规则。对于“简单”表达式,这些规则实际上会告诉您您需要了解的有关表达式求值的所有信息。给定a + b * c,将b乘以c,然后将乘积加到a,因为*的优先级高于+。给定a + b + c,将a添加到b,然后将总和添加到c,因为+从左到右关联。

  2. 除关联性(如第1点所述)外,请尽量不要使用“从左至右”或“从右至左”的评价 。 C没有像从左到右或从右到左的评估那样。 (显然Java是不同的。)

  3. 棘手的地方是副作用。 (当我在第1点说“简单的表达式”时,我的意思基本上是“没有副作用的表达式”。)副作用包括(a)函数调用,(b)带有=的赋值,(c)带有+=-=等,当然(d)使用++--递增/递减。 (如果从变量中获取时很重要(通常仅适用于合格为volatile的变量,我们可以将volatile变量中的(e)提取添加到列表。)通常,您无法确定副作用何时发生。尽量不要在意。只要您不在乎(只要您的程序对影响副作用的顺序不敏感),就无关紧要。但是,如果您的程序 敏感,则可能未定义。 (请参阅下面的第4点和第5点中的更多内容。)

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

  5. 对于一类异常,您绝不能具有试图更改也在同一表达式的其他位置使用的变量的副作用。 (例如:a == --a。)如果这样做,则表达式未定义。例外情况是使用访问的值来计算要存储的值时,例如i = i + 1

答案 1 :(得分:1)

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

C standard的第6.5.13p4节中详细介绍了有关逻辑AND运算符:

  

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

对于此表达式:

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

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

但是此表达式:

if (a == --a)

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

答案 2 :(得分:0)

带有“逻辑和”运算符的(a-- == 10 && a-- == 9)是格式正确的表达式(没有a++ + a++中未定义的行为)。

C标准规定了“逻辑和” /“逻辑或”运算符:

  

保证从左到右的评估;后面有一个序列点   第一个操作数的求值。

因此,第一个子表达式a-- == 10的所有副作用在第二个子表达式a-- == 9评估之前就已完成。 在评估第二个子表达式之前,a9