How do Prefix (++x) and Postfix (x++) operations work?
有人能告诉我前缀/后缀操作符是如何工作的吗?我在网上找了很多东西,但什么都没找到。
据我所知,prefex首先递增,然后执行操作,然后进行赋值。后缀将首先执行操作,然后进行赋值,然后进行递增。
但是我的代码有点问题:
1 2 3 | int x, y; x = 1; y = x + x++; // (After operation y = 2)(x=2) |
但是当我这样做的时候:
1 | y = x++ + x; // (After operation y = 3)(x=2) |
我不知道为什么这些手术会有什么不同。我有两个问题:
你能解释一下区别吗?
这如何应用于其他运算符前缀?
这个问题被问到相当多。请注意,每次有人问这个问题,很多人都会给出错误的答案。很多人对这些操作人员的工作方式都有错误的想法,包括那些写编程书,从而教别人错误的人。仔细阅读这里的其他答案。
有关C行为的正确分析,请参见:
我++和我的区别是什么?
对于C++,任何行为都是正确的行为,在那些你观察到副作用的情况下。C++没有定义增量的副作用何时可见。任何两个编译器都可以做不同的事情。
一个很好的规则是不依赖于在任何语言中发生副作用的顺序,但是在C++中当然不依赖它,因为它是不可靠的。
查看您的具体案例:
1 2 3 | 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中,增量赋值必须在计算增量值之后和使用原始值之前进行。(从执行线程观察时;如果您试图从另一个或多个线程观察此内容,则所有赌注都将取消。)
在第二个示例中:
1 | 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。
- 在c中,
+ 的操作数按从左到右的顺序进行计算。 - 在C和C++中,
+ 操作数的求值顺序是未指定的。
对于C您的示例工作如下:
1 2 3 4 5 6 7 8 9 |
在C和C++中:未指定输出。
参考-C++ 03标准:
第5节:表达,第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.
在C99第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."
在这两种情况下,增量都是在使用x之后应用的。首先,评估如下:Y=1+1(增加到2)
在第二
Y=1(增加到2)+2。
这就是为什么你有不同的答案。
表达式
如果我们把讨论局限于整型操作数,那么
1 2 | x = 0; y = x++; |
结果将是
对于
1 2 | x = 0; y = ++x; |
结果将是
C和C++与C语言的区别在于当操作数被评估和应用了副作用时。C保证表达式中的操作数总是从左到右进行计算。C和C++只保证EDOCX1、14、EDCOX1、15、EDCOX1、16、逗号和函数调用EDOCX1×17操作符的左到右的评估-对于所有其他操作符,操作数被评估的顺序是未指定的。
类似地,在Cα中,EDCX1〔0〕和EDCX1〔1〕的副作用将在表达后立即被应用,而C和C++仅要求在下一个序列点之前应用副作用。
C的评价规则保证EDCOX1、20、EDCOX1、21、EDCX1、22等的表达式是明确定义的,而C和C++语言定义明确地表示这样的表达式会导致未定义的行为(任何结果都是可能的)。
X+X++和X++X是你不想依赖的病理性副作用病例的一个例子。x++和++x都是增量x,但在添加x时,计算顺序是未定义的-编译器可以选择它首先计算的"边"。
考虑:
1 | y = x + x++; |
无论它的行为是否被定义(它在C和C++中都是未定义的,显然它在C语言中是很好定义的),不管你想做什么,都有更好的方式来表达它。
如果你假设严格的从左到右评估,那么上面的内容可以写成:
1 2 | y = x * 2; x ++; |
对于任何知道
或者,如果您不相信编译器生成有效的代码,可以编写
如果你坚持,你甚至可以写:
1 | y = x++ * 2; |
这对我个人的口味来说有点简明扼要,但还是很明确。
如果你想理解别人的代码(诚然,这是程序员花费大量时间做的事情),那么理解复杂的表达式可能很重要。但是,当您编写自己的代码时,清晰性比保存击键(或显示您对运算符优先级图表的了解程度)更重要。