CIL之——入栈和出栈顺序

来源:互联网 发布:mac virtualbox 鼠标 编辑:程序博客网 时间:2024/05/22 06:20

或许大家都听说过,栈是先进后出,队列是先进先出,那CIL代码中入栈和出栈是怎么进行的呢?下面让我们一窥究竟吧!
先看一段简单的CIL代码:

.class public Program extends [mscorlib]System.Object{    .method public static void Show()    {        .entrypoint        .maxstack 3        .locals init(            string info        )        ldstr "Name:{0} Age:{1}"        ldstr "Guo"        box string        ldc.i4 12        box int32        call string [mscorlib]System.String::Format(string,object,object)        stloc.0                 ldloc.0        call void [mscorlib]System.Console::WriteLine(string)        call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()        ret    }}

上述CIL代码对应的C#代码如下:

public class Program{    public static void Show()    {        string info = string.Foramt("Name:{0} Age:{1}","Guo",12);        Console.WriteLine(info);        Console.ReadKey();    }}

下面开始分析入栈和出栈的顺序:

ldstr "Name:{0} Age:{1}"ldstr "Guo"box stringldc.i4 12box int32

执行完毕后堆栈中的内容从上到下依次是:12、”Guo”、”Name:{0} Age:{1}”,由于最先入栈的值会处于栈底位置,所以堆栈中的内容从上到下如图:
这里写图片描述
call string [mscorlib]System.String::Format(string,object,object)需要三个参数,所以要从堆栈中弹出三个值。此时12处于栈顶位置,所以首先被弹出,那12被弹出之后是放到string.Format()第1个参数的位置上吗?如果第1个弹出的值放到第1个参数的位置,第2个弹出的值放到第2个参数的位置,第3个弹出的值放到第3个参数的位置,那对应的C#代码应该是这样的:

string info = string.Foramt(12,"Guo","Name:{0} Age:{1}");

然而实际上生成的C#代码应该是这样的:

string info = string.Foramt("Name:{0} Age:{1}","Guo",12);

说明第1个弹出的值放到了最后1个参数的位置,第2个弹出的值放到了倒数第2个参数的位置,第3个弹出的值放到了第1个参数的位置。有一个简单的方法来快速判断方法各个参数对应的值是什么,CIL代码中各参数入栈的先后顺序是:”Name:{0} Age:{1}”、”Guo”、12,将堆栈中的值赋值给方法所需的各个参数后从第1个参数开始方法各个参数的值依次是:”Name:{0} Age:{1}”、”Guo”、12,说明第1个入栈的值就是方法第1个参数的值,第2个入栈的值就是方法第2个参数的值,以此类推。
这就是入栈和出栈的顺序,以及方法需要多个参数时,栈顶的值被弹出后该放到第几个参数的位置上,不知道各位看明白了吗?有意见请留言。