下面的代码(可用作控制台应用程序):
static void Main(string[] args)
{
int i = 0;
i += i++;
Console.WriteLine(i);
Console.ReadLine();
}
i的结果是0。我以为会有2个(和我的一些同事一样)。可能编译器创建了某种结构,导致i为零。
我期望2的原因是,在我的思路中,右边的语句会先求值,使I加1。然后加上i,因为i已经是1了,所以是1加1。所以1 + 1 = 2。很明显,事实并非如此。
你能解释编译器做什么或者在运行时发生了什么吗?为什么结果是零?
某种免责声明:我非常清楚您不会(而且可能不应该)使用此代码。我知道我永远不会。尽管如此,我觉得了解它为什么会以这样的方式工作以及究竟发生了什么是很有趣的。
这样的:
int i = 0;
i += i++
可以看作是你所做的(以下是一个粗略的简化):
int i = 0;
i = i + i; // i=0 because the ++ is a postfix operator and hasn't been executed
i + 1; // Note that you are discarding the calculation result
实际发生的事情比这更复杂——看看MSDN, 7.5.9后缀增减操作符:
形式为x++或x——的后缀递增或递减操作的运行时处理由以下步骤组成:
如果x被归为变量:
对X求值以生成变量。
保存x的值。
所选操作符将以保存的x值作为参数调用。
运算符返回的值存储在x求值所给出的位置中。
保存的x值成为操作的结果。
注意,由于优先级的顺序,后缀++出现在+=之前,但结果最终未被使用(因为使用了i的前一个值)。
更彻底地将i+ = i++分解为组成它的各个部分需要知道+=和++都不是原子操作(也就是说,它们都不是单个操作),即使它们看起来像是原子操作。这些实现的方式涉及到临时变量,在操作发生之前复制i -每个操作一个。(我将分别为++和+=使用的临时变量使用iAdd和iAssign的名称)。
所以,更接近实际情况的近似是:
int i = 0;
int iAdd = i; // Copy of the current value of i, for ++
int iAssign = i; // Copy of the current value of i, for +=
i = i + 1; // i++ - Happens before += due to order of precedence
i = iAdd + iAssign;
上面的答案有很多很好的推理,我只是做了一个小测试,想和你分享
int i = 0;
i+ = i++;
这里result i显示0 result。
现在考虑以下情况:
案例1:
i = i++ + i; //Answer 1
之前我认为上面的代码类似于这个,所以第一眼看答案是1,而这个I的真正答案是1。
案例2:
i = i + i++; //Answer 0 this resembles the question code.
这里的增量操作符没有出现在执行路径中,不像前面的情况,i++有机会在加法之前执行。
我希望这对你有所帮助。谢谢
这只是从左到右、自底向上的抽象语法树的计算。从概念上讲,表达式的树是从上到下遍历的,但是当递归从树的底部弹出时,计算就展开了。
// source code
i += i++;
// abstract syntax tree
+=
/ \
i ++ (post)
\
i
计算从考虑根节点+=开始。这是这个表达式的主要组成部分。必须计算+=的左操作数,以确定存储变量的位置,并获得前值为零。接下来,右边必须求值。
右边是一个后递增的++操作符。它有一个操作数i,它既作为值的来源,也作为值的存储位置进行计算。运算符对i求值,找到0,然后将1存储到该位置。它根据返回先验值的语义返回先验值0。
现在控制回到+=运算符。现在它有了完成操作的所有信息。它知道存储结果的位置(i的存储位置)以及先前的值,并且它有要添加到先前值的值,即0。所以i最后是0。
像Java一样,c#通过固定求值顺序,清除了C语言中一个非常愚蠢的方面。从左到右,自底向上:程序员可能期望的最明显的顺序。