zoukankan      html  css  js  c++  java
  • 一句C#代码的分析.

    题记:本文纯粹是出于研究的目的,实际上下面的那种写法是根本不被提倡,也不会有人使用的.代码的优劣在于保证性能和程序扩展性的情况下,本身表述清晰与否,一味的追求简化是没有任何好处的,除了让你自己觉得很cool.当然,读你代码的人绝对不会那么认为.


    昨天在CSDN首页看到一个帖子,问,i=0;i=i++;最后得出的i等于多少?
    答案很容易得出,Console.WriteLine(i)可以看到是0.

    答案当然不是我们所关注的,为什么会是0呢?如果是i=0;j=i++;那任何人都能得出j=0这个结果,但是这里是给i自己赋值,但是i++这个自增操作又确实执行了,那最后为什么会是i=0呢?隐约觉得应该是出栈顺序造成的结果,猜测是没有意义的,就让我们看看IL代码到底是怎么回事.

    这是一段简单的C#代码:

     static void Main(string[] args)
            
    {
                
    int i = 0;
                i 
    = i++;
                Console.WriteLine(i);
            }



    对应的IL代码如下:
    .method private hidebysig static void  Main(string[] args) cil managed
    {
      .entrypoint
      
    // Code size       17 (0x11)
      .maxstack  
    3
      .locals init (
    [0] int32 i)
      IL_0000:  nop             
      IL_0001:  ldc.i4.
    0   
      IL_0002:  stloc.
    0    
      IL_0003:  ldloc.
    0   
      IL_0004:  dup       
      IL_0005:  ldc.i4.
    1  
      IL_0006:  
    add          
      IL_0007:  stloc.
    0   
      IL_0008:  stloc.
    0   
      IL_0009:  ldloc.
    0 
      IL_000a:  call       void 
    [mscorlib]System.Console::WriteLine(int32)
      IL_000f:  nop
      IL_0010:  ret
    // end of method Program::Main


    下面让我们分析一下这段IL代码.
    到IL_003为止,这里实现了一次数据的入栈操作,即把变量v0的值push到了ES寄存器里.对应的C#代码是int i = 0;
    此时的栈情况如下:
    [0] //此时v0=0

    然后执行了dup操作,复制栈顶元素,这里对应的操作我们可以理解为是i = i++;中的右边i的出现.
    此时的栈的情况如下:
    [0,0] //v0=0

    接下来是在ES中再申请4byte的空间,值为1.注意,这里并未把值赋给变量,因为这正是常量的申明.
    栈情况如下:
    [v0,0,1] //v0=0
    这里的1的申明实际上是i++操作引起的.单独的i++等价i+=1;如果我们查看IL的话,也会发现两者是一模一样的

    随后就进入了关键的部分:操作和出栈.
    add执行的加操作,需要两个参数,因为结果依然是在ES中存储中,因此操作完后,栈的情况如下:
    [0,0+1]
    到现在,已经很清楚了,接下来的两次出栈做的是同一件事,弹出栈顶元素,赋给v0.如下:
    [0,0+1]-->pop 1 to v0,v0 = 1;
    [0]-->pop 0 to v0,v0 = 0;
    v0正是最终i的值,为0.

    疑点:
    为何最后会有两次出栈操作?
    答案是,在i = i++;中实际上有两部操作,i = 右边(未知数);i = i + 1;因此,必然存在两次出栈.

    最后,实际上在C/C++中i=i++后,得出的结果为1,至于为什么,即使我们不反汇编也应该明白,肯定是出栈或入栈的顺序导致的,有兴趣的朋友不妨去试着分析一下:)

  • 相关阅读:
    7.1MongoDB之索引
    7.1MongoDB之排序
    6.30MongoDB之Limit与Skip方法
    6.30Java连接MongoDB进行操作练习
    6.30MongoDB之$type操作符
    6.30MongoDB之条件操作符
    6.30MongoDB之"查"
    6.29MongoDB之"改"
    c# 调用jar包
    sql server SQL 调试:无法启动 T-SQL 调试。未能附加到 SQL Server 进程
  • 原文地址:https://www.cnblogs.com/wuxilin/p/501615.html
Copyright © 2011-2022 走看看