前缀 (++x) 和后缀 (x++) 操作如何工作?

发布于 2024-12-10 08:54:37 字数 422 浏览 1 评论 0原文

有人能告诉我前缀/后缀运算符是如何工作的吗?我在网上查了很多但没有找到任何东西。

据我所知,prefex 首先递增,然后执行操作,然后分配。
Postfix会先进行运算,然后赋值,然后递增。

但是我的代码遇到了一些麻烦:

int x, y;
x = 1;
y = x + x++; // (After operation y = 2)(x=2)

但是当我这样做时:

y = x++ + x; // (After operation y = 3)(x=2)

我不确定为什么这些操作会有所不同。我有两个问题:

  • 您能解释一下其中的区别吗?

  • 这如何应用于其他运算符前缀?

Can someone tell me how prefix / postfix operators really work? I've been looking online a lot but haven't found anything.

From what I can tell prefex first increments, then does the operation and then assigns.
Postfix would do the operation first, then assign and then increment.

But I'm having a bit of trouble with my code:

int x, y;
x = 1;
y = x + x++; // (After operation y = 2)(x=2)

However when I do:

y = x++ + x; // (After operation y = 3)(x=2)

I'm not sure why these operations would be any different. I have two questions:

  • Could you explain the difference?

  • How does this apply to the other operator Prefix?

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

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

发布评论

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

评论(7

深海蓝天 2024-12-17 08:54:37

这个问题被问了很多。请注意,每次有人问这个问题时,都会有很多人发布错误的答案。许多人对这些运算符的工作原理有错误的想法,包括那些编写编程书籍并因此向其他人传授错误的人。仔细阅读这里的其他答案。

有关 C# 行为的正确分析,请参阅:

i++ 和 ++i 之间有什么区别?

对于 C++ 来说,在您观察到副作用的情况下,任何行为都是正确的行为。 C++ 没有定义增量的副作用何时可见。任何两个编译器都可以以不同的方式执行此操作。

一个需要遵循的好规则是不要依赖任何语言中副作用发生的顺序,但是当然不要在 C++ 中依赖它,因为它不可靠。

查看您的具体情况:

int x, y;     
x = 1;     
y = x + x++; 

您报告 x 和 y 都是 2。这在 C# 中是正确的。在 C# 中,正确的行为是:

  • 将 y 计算为变量
  • 将 x 计算为值——它是 1
  • 将 x++ 计算为值。这将 x 作为变量进行计算,然后取其原始值 1,然后递增该值,即 2,然后将 2 赋给 x,然后得出原始值,即 1。
  • 评估 1 + 1,即 2
  • 将 2 赋给 y。

所以在 C# 中 x 和 y 都是 2。

C++ 可以做同样的事情,但允许按从右到左的顺序计算加法。也就是说,允许执行以下操作:

  • 将 x++ 计算为一个值。这将 x 作为一个变量进行计算,然后取其原始值 1,然后递增该值,即 2,然后将 2 赋给 x,然后得出原始值,即 1。
  • 将 x 计算为一个值 - 它2
  • 计算 1 + 2,即 3
  • 计算 y 作为变量,
  • 将 3 赋给 y。

C++ 也可以这样做:

  • 将 x++ 计算为一个值。这将 x 计算为变量,然后取其原始值 1,然后递增该值,即 2 ...此处缺少步骤...然后得出原始值,即 1。
  • 将 x 计算为一个值-- 1
  • 评估 1 + 1,即 2
  • 将 2 分配给 x -- 之前缺少的步骤。
  • 将 y 计算为变量,
  • 将 2 赋给 y。

因此,在 C++ 中,您可以将 y 设为 3 或 2,具体取决于编译器编写者的想法。在 C# 中,您总是得到 y 为 2。在 C++ 中,增量赋值可以在任何时间发生,只要它确实发生即可。在 C# 中,增量赋值必须发生在计算增量值之后且使用原始值之前。 (当从执行线程观察时;如果您尝试从另一个或多个线程观察这些东西,那么所有的赌注都会被取消。)

在第二个示例中:

y = x++ + x; 

在 C# 中,所需的行为是:

  • 将 y 计算为变量
  • 将 x++ 计算为值。这将 x 作为一个变量进行计算,然后取其原始值 1,然后递增该值,即 2,然后将 2 赋给 x,然后得出原始值,即 1。
  • 将 x 计算为一个值 - 它is 2
  • 计算 1 + 2,即 3
  • 将 3 赋值给 y。

因此,C# 中的正确答案是 y 为 3,x 为 2。

同样,C++ 可以按任意顺序执行这些步骤。 C++ 允许执行以下操作:

  • 将 x 计算为一个值——它是 1
  • 将 x++ 计算为一个值。这将 x 作为变量进行计算,然后取其原始值 1,然后递增该值,即 2,然后将 2 赋给 x,然后得出原始值,即 1。
  • 计算 1 + 1,即 2
  • 将 y 计算为变量,
  • 将 2 赋给 y。

同样,在 C++ 中,正确答案是 y 是 2 或 3,具体取决于编译器编写者的想法。在 C# 中,正确答案是 y 是 3。

This question gets asked a fair amount. Be warned that every time someone asks this question a great many people post incorrect answers. Lots of people have incorrect ideas about how these operators work, including people who write programming books and thereby teach other people falsehoods. Read the other answers here very carefully.

For a correct analysis of the C# behaviour, see:

What is the difference between i++ and ++i?

For C++ any behaviour is correct behaviour, in those cases where you are observing a side effect. C++ does not define when the side effect of the increment is visible. Any two compilers can do it differently.

A good rule to follow is to not rely on the order in which side effects happen in any language, but certainly do not rely on it in C++, because it is not reliable.

To look at your specific case:

int x, y;     
x = 1;     
y = x + x++; 

You report that x and y are both 2. That is correct in C#. In C# the correct behaviour is:

  • evaluate y as a variable
  • evaluate x as a value -- it is 1
  • evaluate x++ as a value. This evaluates x as a variable, then takes its original value which is 1, then increments that value, which is 2, then assigns 2 to x and then results in the original value, which is 1.
  • evaluate 1 + 1, which is 2
  • assign 2 to y.

So x and y are both 2 in C#.

C++ can do the same thing, but it is permitted to evaluate the addition in right-to-left order. That is, it is permitted to do:

  • evaluate x++ as a value. This evaluates x as a variable, then takes its original value which is 1, then increments that value, which is 2, then assigns 2 to x and then results in the original value, which is 1.
  • evaluate x as a value -- it is 2
  • evaluate 1 + 2, which is 3
  • evaluate y as a variable
  • assign 3 to y.

C++ is also permitted to do this:

  • evaluate x++ as a value. This evaluates x as a variable, then takes its original value which is 1, then increments that value, which is 2 ... step missing here ... and then results in the original value, which is 1.
  • evaluate x as a value -- it is 1
  • evaluate 1 + 1, which is 2
  • assigns 2 to x -- the step that was missing before.
  • evaluate y as a variable
  • assign 2 to y.

So in C++, you can get y as 3 or 2, depending on the whim of the compiler writer. In C# you always get that y is 2. In C++, the increment's assignment can happen at any time, as long as it does happen. In C#, the increment's assignment must happen after the incremented value is computed and before the original value is used. (When observed from the executing thread; if you are trying to observe this stuff from another thread or threads, all bets are off.)

In your second example:

y = x++ + x; 

In C# the required behaviour is:

  • evaluate y as a variable
  • evaluate x++ as a value. This evaluates x as a variable, then takes its original value which is 1, then increments that value, which is 2, then assigns 2 to x and then results in the original value, which is 1.
  • evaluate x as a value -- it is 2
  • evaluate 1 + 2, which is 3
  • assign 3 to y.

So the correct answer in C# is that y is 3 and x is 2.

Again, C++ can do these steps in any order. C++ is permitted to do:

  • evaluate x as a value -- it is 1
  • evaluate x++ as a value. This evaluates x as a variable, then takes its original value which is 1, then increments that value, which is 2, then assigns 2 to x and then results in the original value, which is 1.
  • evaluate 1 + 1, which is 2
  • evaluate y as a variable
  • assign 2 to y.

Again, in C++ the correct answer is that y is 2 or 3, depending on the whim of the compiler writer. In C# the correct answer is that y is 3.

一梦等七年七年为一梦 2024-12-17 08:54:37
  • 在 C# 中,+ 的操作数按从左到右的顺序进行计算。
  • 在 C 和 C++ 中,+ 操作数的求值顺序是未指定的。

对于 C#,您的示例的工作方式如下:

 y = x + x++;
     ^ x is 1
         ^ x is increased to 2, but the postfix increment returns the old value (1)
 y = 2

 y = x++ + x;
     ^ x becomes 2, but postfix increment returns the old value (1)
           ^ x is now 2 here
 y = 3
  • In C# the operands of + are evaulated in left-to-right order.
  • In C and C++ the order of evaluation for the operands of + is unspecifed.

For C# your examples work as follows:

 y = x + x++;
     ^ x is 1
         ^ x is increased to 2, but the postfix increment returns the old value (1)
 y = 2

 y = x++ + x;
     ^ x becomes 2, but postfix increment returns the old value (1)
           ^ x is now 2 here
 y = 3
掩耳倾听 2024-12-17 08:54:37

在 C 和 C++ 中:
输出为未指定

参考 - C++03 标准:

第 5 节:表达式,第 4 段:

除非另有说明[例如&&的特殊规则]和 ||]、各个运算符的操作数和各个表达式的子表达式的求值顺序以及副作用发生的顺序均未指定。

在 C99 第 6.5 节中。

“运算符和操作数的分组由语法指示。72) 除非稍后指定(对于函数调用 ()、&&、||、?: 和逗号运算符),否则子表达式的求值和副作用发生的顺序都未指定。”

In C and C++:
The output is Unspecified.

Reference - C++03 Standard:

Section 5: Expressions, Para 4:

except where noted [e.g. special rules for && and ||], the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is Unspecified.

In C99 Section 6.5.

"The grouping of operators and operands is indicated by the syntax.72) Except as specified later (for the function-call (), &&, ||, ?:, and comma operators), the order of evaluation of subexpressions and the order in which side effects take place are both unspecified."

看海 2024-12-17 08:54:37

在这两种情况下,增量都是在使用 x 之后应用的。首先,其评价如下:
y = 1 + 1(增加到2)

在第二个

y = 1(增加到2)+ 2。

这就是为什么你得到不同的答案。

In both cases, the increment was applied after the x was used. In the first, it was evaluated as follows:
y = 1 + 1 (incremented to 2)

in the second

y = 1 (incremented to 2) + 2.

That's why you got different answers.

¢好甜 2024-12-17 08:54:37

表达式x++++x 都有结果(或值)和副作用

如果我们将讨论限制在整型操作数上,则 x++结果就是 x 的当前值。 副作用是将x增加1。因此,给定代码,

x = 0;
y = x++;

结果将是x == 1和y< /code> == 0(假设 x 和 y 是整型)。

对于++x结果是1加上x的当前值。 副作用是将x增加1。因此,给定代码,

x = 0;
y = ++x;

结果将是x == y > == 1.

C 和 C++ 与 C# 的区别在于何时计算操作数以及何时应用副作用。 C# 保证表达式中的操作数始终按从左到右的顺序求值。 C 和 C++ 仅保证 &&||?:、逗号和 function- 的从左到右计算call () 运算符 - 对于所有其他运算符,计算操作数的顺序未指定

类似地,在 C# 中,x++++x 的副作用将在表达式求值后立即应用,而 C 和 C++ 仅要求副作用是在下一个序列点之前应用。

C# 的计算规则保证像 x = x++a = b++ * b++a[i] = i++ 这样的表达式是很好的 -已定义,而 C 和 C++ 语言定义明确表示此类表达式会导致未定义行为(任何结果都是可能的)。

The expressions x++ and ++x have both a result (or value) and a side effect.

If we restrict our discussion to integral type operands, the result of x++ is whatever the current value of x is. The side effect is to increment x by 1. Thus, given the code

x = 0;
y = x++;

the result will be x == 1 and y == 0 (assuming x and y are integral types).

For ++x, the result is 1 plus the current value of x. The side effect is to increment x by 1. Thus, given the code

x = 0;
y = ++x;

the result will be x == y == 1.

What distinguishes C and C++ from C# is when operands are evaluated and when the side effects are applied. C# guarantees that operands in an expression are always evaluated left-to-right. C and C++ only guarantee left-to-right evaluation for the &&, ||, ?:, comma, and function-call () operators - for all other operators, the order in which operands are evaluated is unspecified.

Similarly, in C#, the side effects of x++ and ++x will be applied immediately after the expression has been evaluated, whereas C and C++ only require that the side effect be applied before the next sequence point.

C#'s rules on evaluation guarantee that the expressions like x = x++, a = b++ * b++, and a[i] = i++ are well-defined, whereas the C and C++ language definitions explicitly say such expressions result in undefined behavior (any result is possible).

柳若烟 2024-12-17 08:54:37

x + x++ 和 x++ + x 是您不想依赖的病理副作用案例的示例。 x++ 和 ++x 都会递增 x,但在添加 x 时,求值顺序是未定义的 - 编译器可以选择首先求值的“一侧”。

x + x++ and x++ + x are an example of pathological side-effects cases you don't want to depend on. x++ and ++x both increment x, but in adding x the order of evaluation is undefined - the compiler can choose which 'side' it evaluates first.

掌心的温暖 2024-12-17 08:54:37

考虑一下:

y = x + x++;

无论它的行为是否已定义(在 C 和 C++ 中未定义;显然在 C# 中定义良好),无论您想要做什么,都一定有更好的方式来表达它。

如果您假设严格从左到右评估,那么上面的内容可以写为:

y = x * 2;
x ++;

对于任何知道 =* 的读者来说,含义是清晰且明确的,和 ++ 意味着,你的代码的未来维护者不会试图追捕你。

或者您可以编写 x + xx << 1 如果您不信任编译器生成有效的代码,但这种不信任通常是错误的。

如果你坚持的话,你甚至可以这样写:

y = x++ * 2;

对于我个人的口味来说,这有点简洁,但仍然很明确。

如果您想理解别人的代码(诚然,这是程序员花费大量时间做的事情),那么理解复杂的表达式可能很重要。但是,当您编写自己的代码时,清晰度比节省击键次数(或展示您对运算符优先级图表的了解程度)更重要。

Consider:

y = x + x++;

Whether its behavior is defined or not (it's undefined in C and C++; apparently it's well defined in C#), whatever it is you're trying to do, there's bound to be a better way to express it.

If you're assuming strict left-to-right evaluation, then the above could be written as:

y = x * 2;
x ++;

The meaning is clear and unambiguous to any reader who knows what =, *, and ++ mean, and future maintainers of your code won't be tempted to hunt you down.

Or you could write x + x or x << 1 if you don't trust the compiler to generate efficient code, but such mistrust is usually misplaced.

If you insist, you could even write:

y = x++ * 2;

That's a little terse for my personal tastes, but it's still unambiguous.

If you want to understand somebody else's code (which admittedly is something programmers spend a great deal of time doing), then understanding convoluted expressions can be important. But when you're writing your own code, clarity is more important than saving keystrokes (or showing off how well you know the operator precedence charts).

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