C# 对于i=0,为什么(i+;=i+;+;)等于0?
采用以下代码(可用作控制台应用程序):C# 对于i=0,为什么(i+;=i+;+;)等于0?,c#,.net,C#,.net,采用以下代码(可用作控制台应用程序): i的结果为0。我预期会有2个(正如我的一些同事所做的那样)。编译器可能会创建某种结构,导致i为零 我期望2的原因是,在我的思路中,首先计算右边的语句,将I加1。而不是添加到i中。因为我已经是1了,所以它将1与1相加。所以1+1=2。很明显,事情并不是这样的 你能解释一下编译器在运行时做什么或发生什么吗?为什么结果是零 某种形式的免责声明:我绝对知道您不会(也可能不应该)使用此代码。我知道我永远不会。尽管如此,我发现了解它为何以这种方式运行以及到底发生了什么
i
的结果为0。我预期会有2个(正如我的一些同事所做的那样)。编译器可能会创建某种结构,导致i
为零
我期望2的原因是,在我的思路中,首先计算右边的语句,将I加1。而不是添加到i中。因为我已经是1了,所以它将1与1相加。所以1+1=2。很明显,事情并不是这样的
你能解释一下编译器在运行时做什么或发生什么吗?为什么结果是零
某种形式的免责声明:我绝对知道您不会(也可能不应该)使用此代码。我知道我永远不会。尽管如此,我发现了解它为何以这种方式运行以及到底发生了什么是很有趣的。后修复增量操作符,
++
,在表达式中为变量提供一个值,然后再次执行您为I
指定的增量返回零(0)值,以覆盖递增的一(1),所以你得到的是零。您可以在(MSDN)中阅读有关增量运算符的更多信息。因为i++
首先返回值,然后递增它。但是在i设置为1之后,您可以将其设置回0将等于零,因为它随后执行++
i++=++i代码>将在执行此操作之前执行此操作:
int i = 0;
i += i++
可以看到你在做什么(以下是一个严重的过度简化):
实际发生的事情远不止这些——看看MSDN:
形式为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;
++后缀在递增之前计算i
,而+=
只计算i
一次
因此,0+0=0,因为i
在递增之前被计算和使用,因为使用了++
的后缀格式。要先递增i
,请使用前缀形式(++i
)
(还有,请注意:您应该只得到1,因为0+(0+1)=1)
参考文献:(+=)
(++)首先,i++
返回0。然后,i
增加1。最后,将i
设置为i
的初始值0加上返回的值i++
,该值也为零。0+0=0。变量后的++运算符使其成为后缀增量。递增发生在语句中的所有其他内容之后,即加法和赋值。相反,如果您将++放在变量之前,它将在计算i的值之前发生,并给出预期的答案。有两个选项:
第一个选项:如果编译器按照如下方式读取语句
i++;
i+=i;
那么结果是2
为了
结果是1
int i = 0;
i += i++;
评估结果如下:
Stack<int> stack = new Stack<int>();
int i;
// int i = 0;
stack.Push(0); // push 0
i = stack.Pop(); // pop 0 --> i == 0
// i += i++;
stack.Push(i); // push 0
stack.Push(i); // push 0
stack.Push(i); // push 0
stack.Push(1); // push 1
i = stack.Pop() + stack.Pop(); // pop 0 and 1 --> i == 1
i = stack.Pop() + stack.Pop(); // pop 0 and 0 --> i == 0
Stack Stack=新堆栈();
int i;
//int i=0;
stack.Push(0);//推0
i=stack.Pop();//pop 0-->i==0
//i++=i++;
栈.推(i);//推0
栈.推(i);//推0
栈.推(i);//推0
栈。推(1);//推1
i=stack.Pop()+stack.Pop();//pop 0和1-->i==1
i=stack.Pop()+stack.Pop();//pop 0和0-->i==0
i、 e.i
更改两次:一次是由i++
表达式更改,一次是由+=
语句更改
但是+=
语句的操作数是
- 计算
i++
(+=
左侧)之前的值i
,以及
- 计算
i++
之前的值i
(+=
的右侧)
增量后方法类似于
int ++(ref int i)
{
int c = i;
i = i + 1;
return c;
}
因此,基本上,当您调用i++
时,i
是递增的,但在您的情况下返回的是原始值,返回的是0。正在运行的代码的反汇编:
int i = 0;
xor edx, edx
mov dword ptr i, edx // set i = 0
i += i++;
mov eax, dword ptr i // set eax = i (=0)
mov dword ptr tempVar1, eax // set tempVar1 = eax (=0)
mov eax, dword ptr i // set eax = 0 ( again... why??? =\ )
mov dword ptr tempVar2, eax // set tempVar2 = eax (=0)
inc dword ptr i // set i = i+1 (=1)
mov eax, dword ptr tempVar1 // set eax = tempVar1 (=0)
add eax, dword ptr tempVar2 // set eax = eax+tempVar2 (=0)
mov dword ptr i, eax // set i = eax (=0)
等效代码
它编译为与以下代码相同的代码:
int i, tempVar1, tempVar2;
i = 0;
tempVar1 = i; // created due to postfix ++ operator
tempVar2 = i; // created due to += operator
++i;
i = tempVar1 + tempVar2;
第二个代码的反汇编(只是为了证明它们是相同的)
打开拆解窗口
大多数人不知道,甚至不记得,他们可以使用Visual Studio反汇编窗口查看最终的内存中汇编代码。它显示正在执行的机器代码,而不是CIL
调试时使用此选项:
Debug(菜单)->Windows(子菜单)->反汇编
那么postfix++到底发生了什么呢?
后缀++告诉我们要在求值后增加操作数的值。。。每个人都知道。。。什么
int ++(ref int i)
{
int c = i;
i = i + 1;
return c;
}
int i = 0;
xor edx, edx
mov dword ptr i, edx // set i = 0
i += i++;
mov eax, dword ptr i // set eax = i (=0)
mov dword ptr tempVar1, eax // set tempVar1 = eax (=0)
mov eax, dword ptr i // set eax = 0 ( again... why??? =\ )
mov dword ptr tempVar2, eax // set tempVar2 = eax (=0)
inc dword ptr i // set i = i+1 (=1)
mov eax, dword ptr tempVar1 // set eax = tempVar1 (=0)
add eax, dword ptr tempVar2 // set eax = eax+tempVar2 (=0)
mov dword ptr i, eax // set i = eax (=0)
int i, tempVar1, tempVar2;
i = 0;
tempVar1 = i; // created due to postfix ++ operator
tempVar2 = i; // created due to += operator
++i;
i = tempVar1 + tempVar2;
int i, tempVar1, tempVar2;
i = 0;
xor edx, edx
mov dword ptr i, edx
tempVar1 = i; // created due to postfix ++ operator
mov eax, dword ptr i
mov dword ptr tempVar1, eax
tempVar2 = i; // created due to += operator
mov eax, dword ptr i
mov dword ptr tempVar2, eax
++i;
inc dword ptr i
i = tempVar1 + tempVar2;
mov eax, dword ptr tempVar1
add eax, dword ptr tempVar2
mov dword ptr i, eax
// source code
i += i++;
// abstract syntax tree
+=
/ \
i ++ (post)
\
i
int i = 0;
i += i++;
// Translates to:
i = i + 0; // because post increment returns the current value 0 of i
// Before the above operation is set, i will be incremented to 1
// Now i gets set after the increment,
// so the original returned value of i will be taken.
i = 0;
int a = 1;
int b = a++;
int a = 1;
int b = ++a;
int i = 0;
i += (i++);
i += (++i); // Here 'i' would become two
i=0
i+=i
i=i+1
i=0;
i+=++i
i=2
static int SetSum(ref int a, int b) { return a += b; }
static int Inc(ref int a) { return a++; }
int i = 0;
SetSum(ref i, Inc(ref i));
Console.WriteLine(i); // i is 1
static int Sum(int a, int b) { return a + b; }
static int Set(ref int a, int b) { return a = b; }
int i = 0;
Set(ref i, Sum(i, Inc(ref i)));
Console.WriteLine(i); // i is 0
int i=0;
i+=i++;
int i=0;
i = i + i ++;
int i=0;
i= i + i;
i ++;
int i=0;
i = i + i;
i = i + 1;
int i = 0;
i+ = i++;
i = i++ + i; //Answer 1
i = i + i++; //Answer 0 this resembles the question code.