前缀(++ x)和后缀(x ++)操作如何工作?
谁能告诉我前缀/后缀运算符是如何工作的? 我一直在网上看很多但没找到任何东西。
从我可以告诉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)
我不确定为什么这些操作会有所不同。 我有两个问题:
-
你能解释一下这个区别吗?
-
这如何适用于其他运营商Prefix?
- 在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
这个问题得到了相当多的要求。 请注意,每当有人问这个问题时,很多人都会发布不正确的答案。 许多人对这些操作员的工作方式有不正确的想法,包括编写编程书籍的人,从而教导其他人的谎言。 请仔细阅读其他答案。
有关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。
所以x和y在C#中都是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评估为一个值 – 它是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。
在这两种情况下,在使用x之后应用增量。 在第一个中,它评估如下:y = 1 + 1(增加到2)
在第二
y = 1(递增到2)+ 2。
这就是你得到不同答案的原因。
在C和C ++中:
输出未指定 。
参考 – C ++ 03标准:
第5节:表达式,第4段:
除非注明[例如&&和||的特殊规则],否则单个运算符的操作数和单个表达式的子表达式的评估顺序以及副作用发生的顺序是未指定的。
在C99第6.5节中。
“运算符和操作数的分组由语法表示.72除了后面指定的(对于函数调用(),&&,||,?:和逗号运算符),子表达式的评估顺序和顺序发生副作用的都是未指明的。“
表达式x++
和++x
同时具有结果 (或值)和副作用 。
如果我们将讨论限制为整数类型操作数,则x++
的结果是x++
的当前值。 副作用是将x
增加1.因此,给定代码
x = 0; y = x++;
结果将是x
== 1和y
== 0(假设x
和y
是整数类型)。
对于++x
, 结果是1加上x
的当前值。 副作用是将x
增加1.因此,给定代码
x = 0; y = ++x;
结果将是x
== y
== 1。
C和C ++与C#的区别在于评估操作数和应用副作用时。 C#保证表达式中的操作数始终从左到右进行求值。 C和C ++只保证&&
, ||
从左到右的评估 , ?:
,逗号和函数调用()
运算符 – 对于所有其他运算符, 未指定操作数的计算顺序。
类似地,在C#中, x++
和++x
副作用将在评估表达式后立即应用,而C和C ++仅要求在下一个序列点之前应用副作用。
C#的评估规则保证了像x = x++
, a = b++ * b++
和a[i] = i++
这样的表达式是明确定义的,而C和C ++语言定义明确地说这样的表达式会导致未定义的行为(任何结果都是可能)。
x + x ++和x ++ + x是您不想依赖的病理性副作用病例。 x ++和++ x都增加x,但是在添加x时,评估的顺序是未定义的 – 编译器可以选择首先评估哪个’side’。
考虑:
y = x + x++;
它的行为是否被定义(它在C和C ++中未定义;显然它在C#中定义得很好),无论你想要做什么,都必然有更好的表达方式。
如果您正在进行严格的从左到右的评估,那么上述内容可以写成:
y = x * 2; x ++;
对于任何知道=
, *
和++
意思的读者来说,这个含义是清楚明确的,并且未来的代码维护者也不会想要追捕你。
或者你可以写x + x
或x << 1
如果你不相信编译器生成有效的代码,但这种不信任通常是错误的。
如果你坚持,你甚至可以写:
y = x++ * 2;
这对我的个人品味来说有点简洁,但它仍然毫不含糊。
如果你想了解其他人的代码(这无疑是程序员花费大量时间做的事情),那么理解复杂的表达式可能很重要。 但是当你编写自己的代码时,清晰度比保存键击更重要(或者展示你对运算符优先级图表的了解程度。