C# IL代码中maxstack值的计算

C# IL代码中maxstack值的计算,c#,stack,cil,il,ildasm,C#,Stack,Cil,Il,Ildasm,我有下面的程序来添加这些值。 当我在main方法中调用Add方法并查看ILDASM.EXE时,Maxstack大小为2。取消注释后,maxstack大小变为4 为什么在主方法的情况下,所有变量都没有进入堆栈,因为堆栈大小仅为2,而在Add方法调用的情况下,每个变量都进入堆栈? 在这种情况下,主方法内部的计算是一个接一个地进行的,因此一次只需要两个变量 请澄清我的困惑 static void Main(string[] args) { int x = 2; int y = 3;

我有下面的程序来添加这些值。 当我在main方法中调用Add方法并查看ILDASM.EXE时,Maxstack大小为2。取消注释后,maxstack大小变为4

为什么在主方法的情况下,所有变量都没有进入堆栈,因为堆栈大小仅为2,而在Add方法调用的情况下,每个变量都进入堆栈? 在这种情况下,主方法内部的计算是一个接一个地进行的,因此一次只需要两个变量

请澄清我的困惑

static void Main(string[] args)
{
    int x = 2;
    int y = 3;
    int a = 4;
    int b = 5;
    int c = 6;

    Console.WriteLine(x + y + a + b + c);
    Console.WriteLine(Add(10, 20, 30, 40));
    Console.ReadLine();
}

static int Add(int x, int y, int z, int a)
{
    return x + y + z + a;
}

每个变量初始化:

int x = 2;
将要求值位于堆栈上:(堆栈大小:到目前为止需要1)

这些操作按顺序进行,因此在以下期间,所需的最大堆栈大小仍然为1:

int y = 3;
int a = 4;
int b = 5;
int c = 6;
说到这里:

Console.WriteLine(x + y + a + b + c);
要添加任意两个变量,堆栈大小必须为2:

IL_000b:  ldloc.0 // copy to stack x, max stack size required is still 1.
IL_000c:  ldloc.1 // copy to stack y, max stack size required is 2 now.
IL_000d:  add     // execute add, will cause the sum x + y to be on stack
IL_000e:  ldloc.2 // copy to stack a
IL_000f:  add     // execute add... (adds a to the result of x + y)
....
下面是取消注释Add方法时的差异IL

调用方法时,需要将实例引用推送到堆栈上(这意味着,如果Add方法是非静态的,那么指向其声明类型的实例指针应该推送到堆栈上)

然后,需要传递给方法的每个参数也应该推送到堆栈上

因此,在您的案例中,定义最大堆栈大小的是Add方法的参数数量。将参数添加到此Add方法中,您将看到最大堆栈大小将增加到5:

// method is static so no need to push an instance pointer to the stack
IL_001a:  ldc.i4.s   10 // push to stack
IL_001c:  ldc.i4.s   20 // push to stack
IL_001e:  ldc.i4.s   30 // push to stack
IL_0020:  ldc.i4.s   40 // push to stack
IL_0022:  call       int32 Program::Add(int32,
                                      int32,
                                      int32,
                                      int32)
IL_0027:  call       void [mscorlib]System.Console::WriteLine(int32)

我会稍微调整顶部的措辞-不是声明使用堆栈空间,而是初始化。@Damien_不信者感谢您的审阅和更正。修正它。就像IL不是逐行生成的一样。我的意思是,当x=2接受一个堆栈空间时,为什么不进行其他值声明呢?这是否就像编译器知道它只需要加法,所以堆栈中的2个空间就足够了。@TBAG-
x=2
需要一个堆栈空间-它将
2
推到堆栈上,然后将其从堆栈中弹出到变量
x
中。在这一点上,堆栈再次是空的。内联一个方法体的好处将是大量的IL指令,这主要取决于该方法具有的参数数量。如上所述,调用带有4个参数的静态方法需要5条IL指令。编译器足够聪明,可以在必要时内联内容。不要因此而破坏模块化。
// method is static so no need to push an instance pointer to the stack
IL_001a:  ldc.i4.s   10 // push to stack
IL_001c:  ldc.i4.s   20 // push to stack
IL_001e:  ldc.i4.s   30 // push to stack
IL_0020:  ldc.i4.s   40 // push to stack
IL_0022:  call       int32 Program::Add(int32,
                                      int32,
                                      int32,
                                      int32)
IL_0027:  call       void [mscorlib]System.Console::WriteLine(int32)