C 中的运算符结合性特别是前缀和后缀递增和递减

发布于 2024-08-24 21:52:28 字数 533 浏览 7 评论 0原文

在 C 运算中,结合性是指递增、递减和赋值。

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

完整列表可以在这里找到 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++ 中的 a 等于 1?

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

我很确定在操作关联性方面我不明白一些非常重要的事情。

In C operation associativity is as such for increment, decrement and assignment.

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

The full list is found here Wikipedia Operators in C

My question is when we have

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

Why is a equal to 1 with b++ when the postfix increment operator should happen before the direct assignment?

And why is the prefix increment operator different than the postfix when they are both before the assignment?

I'm pretty sure I don't understand something very important when it comes to operation associativity.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

少年亿悲伤 2024-08-31 21:52:38

正如 AndreyT 已经指出的那样,优先级和关联性不会告诉您求值的顺序。他们只告诉你有关分组的信息。例如,优先级告诉用户 a*b+c 分组为 (a*b)+c 而不是 a*(b+c)。编译器可以按照它认为适合这些表达式的任何顺序自由地计算 abc。结合性告诉您当您具有相同优先级的运算符(通常是相同的运算符)时如何进行分组。例如,它告诉您 abc 相当于 (ab)-c,而不是 a-(bc)(否则,减法是左结合的)。

评估顺序由序列点定义。完整表达式的末尾有一个序列点(除其他外)。在序列点,所有先前的评估必须已经发生,并且后续的评估还没有发生。

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

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

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

a = b;
b = b + 1;

或:

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

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

As AndreyT already pointed out, precedence and associativity don't tell you about order of evaluation. They only tell you about grouping. For example, precedence is what tells use that a*b+c is grouped as (a*b)+c instead of a*(b+c). The compiler is free to evaluate a, b and c in any order it sees fit with either of those expressions. Associativity tells you about grouping when you have operators of the same precedence, most often, the same operators. For example, it's what tells you that a-b-c is equivalent to (a-b)-c, not a-(b-c) (otherwise stated, subtraction is left associative).

Order of evaluation is defined by sequence points. There's a sequence point at the end of a full expression (among other things). At the sequence point, all the previous evaluations have to have taken place, and none of the subsequent evaluations can have taken place yet.

Looking at your specific examples, in a=b++;, the result is mostly from the definition of post-increment itself. A post-increment yields the previous value of the variable, and sometime before the next sequence point, the value of that variable will be incremented. A pre-increment yields the value of the variable with the increment applied. In neither case, however, does that mean the variable has to be incremented in any particular order relative to the assignment. For example, in your pre-increment example, the compiler is entirely free to do something equivalent to:

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

Likewise, in the post-increment version, the variable can be incremented before or after the assignment:

a = b;
b = b + 1;

or:

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

Either way, however, the value assigned to a must be the value of b before it's incremented.

小镇女孩 2024-08-31 21:52:36

运算符优先级和结合性不会告诉您之前发生了什么以及之后发生了什么。运算符优先级/结合性与之无关。在 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 实际上是在end,而在第二种情况下,b 首先递增。但在这两种情况下,a 都会获得相同的正确值 - b 的原始值,这是它应该获得的值。

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

Operator precedence and associativity does not tell you what happens before and what happens after. Operator precedence/associativity has nothing to do with it. In C language temporal relationships like "before" or "after" are defined by so called sequence points and only by sequence points (and that's a totally separate story).

Operator precedence/associativity simply tells you which operands belong to which operators. For example, the expression a = b++ can be formally interpreted as (a = b)++ and as a = (b++). Operator precedence/associativity is this case simply tells you that the latter interpretation is correct and the former is incorrect (i.e. ++ applies to b and not to the result of a = b).

That, once again, does not mean that b should be incremented first. Operator precedence/associativity, once again, has noting to do with what happens "first" and what happens "next". It simply tells you that the result of b++ expression is assigned to a. By definition, the result of b++ (postfix increment) is the original value of b. This is why a will get the original value of b, which is 1. When the variable b will get incremented is completely irrelevant, as long as a gets assigned b's original value. The compiler is allowed to evaluate this expression in any order and increment b at any time: anything goes, as long as a somehow gets the original value of b (and nobody really cares how that "somehow" works internally).

For example, the compiler can evaluate a = b++ as the following sequence of elementary operations

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

or it can evaluate it as follows

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

Note that in the first case b is actually incremented at the end, while in the second case b is incremented first. But in both cases a gets the same correct value - the original value of b, which is what it should get.

But I have to reiterate that the above two examples are here just for illustrative purposes. In reality, expressions like a = ++b and a = b++ have no sequence points inside, which means that from your point of view everything in these expressions happens simultaneously. There's no "before", "after", "first", "next" or "last". Such expressions are "atomic" in a sense that they cannot be meaningfully decomposed into a sequence of smaller steps.

穿透光 2024-08-31 21:52:34

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

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

前缀++a将返回新值即

{ a=a+1; return a; }

这与运算符优先级无关。

(结合性决定了abc是否等于(ab)-ca-(bc)。)

The postfix operator a++ will increment a and then return the original value i.e. similar to this:

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

and the prefix ++a will return the new value i.e.

{ a=a+1; return a; }

This is irrelevant to the operator precedence.

(And associativity governs whether a-b-c equals to (a-b)-c or a-(b-c).)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文