Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 对于i=0,为什么(i+;=i+;+;)等于0?_C#_.net - Fatal编程技术网

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.