5

背景

我知道编译器会“省略int foo = 0;为字段等生成代码,因为内存分配器会将字段初始化为默认值。” 参考

        class Foo
        {
            public int a = 1;
            public int b = 0;
        }
        Foo..ctor:
        IL_0000:  ldarg.0     
        IL_0001:  ldc.i4.1
        IL_0002:  stfld       UserQuery+Foo.a // There is no b.
        IL_0007:  ldarg.0
        IL_0008:  call        System.Object..ctor
        IL_000D:  ret

我也知道“编译器会自动添加.locals init每个使用局部变量的方法,这表明 JIT 必须在开始执行方法之前注入初始化所有局部变量的代码。” 参考

问题

为什么编译器不省略int foo = 0;为局部变量之类的东西生成IL,因为.locals init已经涵盖了这一点?(为了与字段保持一致?)

(我知道 C# 规范需要明确分配局部变量,我可以接受。)

(我引用的链接说明了.locals init需要的原因,以及为什么 C# 规范需要初始化本地变量。但它没有说明为什么必须存在用于初始化默认值的额外 IL 指令。因为验证过程已经得到保证.locals init

void Main()
{
    int a = 0;
    int b = 1;
    int c = 0;
    int d = a + b + c;
    d++;
}

.maxstack 2
.locals init (int a, int b, int c, int d)

IL_0000:  ldc.i4.0    
IL_0001:  stloc.0     // a (Can be optimized away)
IL_0002:  ldc.i4.1    
IL_0003:  stloc.1     // b
IL_0004:  ldc.i4.0    
IL_0005:  stloc.2     // c (Can be optimized away)
IL_0006:  ldloc.0     // a
IL_0007:  ldloc.1     // b
IL_0008:  add         
IL_0009:  ldloc.2     // c
IL_000A:  add         
IL_000B:  stloc.3     // d
IL_000C:  ldloc.3     // d
IL_000D:  ldc.i4.1    
IL_000E:  add         
IL_000F:  stloc.3     // d
4

1 回答 1

1

为什么编译器不省略int foo = 0;为局部变量之类的东西生成IL,因为.locals init已经涵盖了这一点?

为什么要呢?我还没有真正验证这一点,但是如果您删除了不必要的初始化,如果 JIT 编译器生成不同的本机代码,我会感到惊讶。

这意味着将这种优化添加到 C# 编译器的唯一好处是使 JIT 编译稍微快一点(因为它必须处理更少量的 IL 代码)。似乎 C# 编译器的作者虽然为了如此微小的好处而进行这种优化是不值得的。

于 2013-06-24T15:21:07.360 回答