C中的运算符关联性具体为前缀和后缀的递增和递减

时间:2010-03-07 06:44:20

标签: c operation associativity

在C操作中,关联性就是增量,减量和赋值。

  2. postfix ++ and -- 
  3. prefix ++ and -- 
  16. Direct assignment = 

完整列表位于Wikipedia Operators in C

我的问题是我们什么时候

int a, b;

b = 1;
a = b++;

printf("%d", a); // a is equal to 1

b = 1;
a = ++b;

printf("%d", a); //a is equal to 2

为什么在直接赋值之前,后缀增量运算符应该在b ++中等于1?

为什么前缀增量运算符在赋值之前与后缀不同?

我很确定在操作关联性方面我不理解一些非常重要的东西。

3 个答案:

答案 0 :(得分:15)

后缀运算符a++将递增a,然后返回原始值,即类似于:

{ temp=a; a=a+1; return temp; }

并且前缀++a将返回新值,即

{ a=a+1; return a; }

这与运营商优先级无关。

(关联性决定a-b-c是否等于(a-b)-ca-(b-c)。)

答案 1 :(得分:5)

运算符优先级和关联性不会告诉您在之前发生了什么以及之后发生了什么。运算符优先级/关联性与它无关。在C语言中,诸如“之前”或“之后”的时间关系由所谓的序列点由序列点定义(这是一个完全独立的故事)。

运算符优先级/关联性只是告诉您哪些操作数属于哪些运算符。例如,表达式a = b++可以正式解释为(a = b)++a = (b++)。运算符优先级/关联性在这种情况下只是告诉您后一种解释是正确的,前者是不正确的(即++适用于b而不适用于a = b的结果。

再一次,这并不意味着b应该先递增。运算符优先级/关联性再一次与“第一次”发生的事情以及“下一次”发生的事情有关。它只是告诉您b++表达式的结果已分配给a。根据定义,b++(后缀增量)的结果是b原始值。这就是为什么a将获得b原始值,即1.当变量b增加时,完全无关紧要,只要{ {1}}已分配a原始值。允许编译器以任何顺序评估此表达式并随时增加b:只要b以某种方式获得a原始值,任何事情都会发生。 (并且没有人真正关心“某种程度上”如何在内部工作)。

例如,编译器可以将b评估为以下基本操作序列

a = b++

或者它可以按如下方式评估

(1) a := b
(2) b := b + 1

请注意,在第一种情况下,(1) b := b + 1 (2) a = b - 1 实际上在末尾递增,而在第二种情况下,b首先递增。但在这两种情况下,b都会获得相同的正确值 - a的原始值,这是它应该得到的值。

但我必须重申,上述两个例子仅用于说明目的。实际上,像ba = ++b这样的表达式内部没有序列点,这意味着从您的角度来看,这些表达式中的所有内容都会同时发生 。没有“之前”,“之后”,“第一”,“下一个”或“最后”。这种表达在某种意义上是“原子的”,它们不能被有意义地分解成一系列较小的步骤。

答案 2 :(得分:1)

正如AndreyT已经指出的那样,优先级和关联性并没有告诉你评估的顺序。他们只告诉你关于分组的事情。例如,优先级是指使用a*b+c分组为(a*b)+c而不是a*(b+c)的用法。编译器可以按其认为适合的任何顺序自由评估abc。当您拥有相同优先级的运算符(通常是相同的运算符)时,关联性会告诉您有关分组的信息。例如,它告诉您a-b-c等同于(a-b)-c,而不是a-(b-c)(另有说明,减法是左对联的)。

评估顺序由序列点定义。在完整表达式的末尾有一个序列点(除其他外)。在序列点,必须进行所有先前的评估,并且尚未进行任何后续评估。

查看您的具体示例,在a=b++;中,结果主要来自后增量本身的定义。后增量产生变量的先前值,并且在下一个序列点之前的某个时间,该变量的值将递增。预增量会产生应用增量的变量值。然而,在这两种情况下,这都不意味着变量必须以相对于赋值的任何特定顺序递增。例如,在您的预增量示例中,编译器完全可以自由地执行与以下内容相同的操作:

temp = b+1;
a = temp;
b = b + 1;

同样,在后增量版本中,变量可以在赋值之前或之后递增:

a = b;
b = b + 1;

或:

temp = b;
b = b + 1;
a = temp;

但是,无论哪种方式,分配给a的值必须是b之前增加的值。