4

在 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?

当它们都在赋值之前,为什么前缀增量运算符与后缀不同?

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

4

3 回答 3

15

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

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

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

{ a=a+1; return a; }

这与运算符优先级无关。

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

于 2010-03-07T06:48:27.203 回答
6

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

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

再一次,这并不意味着b应该首先增加。再一次,运算符优先级/关联性与“首先”发生的事情和“接下来”发生的事情有关。它只是告诉您b++表达式的结果被分配给a. 根据定义,b++(后缀增量)的结果是 的原始b。这就是为什么a会得到 的原始b,即 1。变量b何时递增完全无关紧要,只要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都会得到相同的正确值 - 的原始值b,这是它应该得到的。

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

于 2010-03-07T06:56:57.257 回答
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递增之前的值。

于 2010-03-07T07:20:36.613 回答