4

例如,当我们声明一个变量时int

int i = 4;

生成以下 IL:

IL_0001:  /* 1A   |                  */ ldc.i4.4

我可以理解 1A 是 4 的十六进制表示,所以我理解正确的是保存十六进制值用于引用它的值还是它意味着不同的东西?

当我声明一个双重变量时:

double d = 12.34;

生成了以下 IL,我无法在其中得到一些东西:

IL_0003:  /* 23   | AE47E17A14AE2840 */ ldc.r8     12.34

23 是怎么来的,这意味着什么,AE47E17A14AE2840这里有什么?

当我声明具有相同值的浮点数时:

float f = 12.34f;

我现在有这个 IL:

IL_000d:  /* 22   | A4704541         */ ldc.r4     12.34

同样的问题在这里以及它是怎么22来的,它的意思是什么A4704541

4

3 回答 3

8

我认为了解 ildasm 告诉你的内容很重要。管道字符前面的字节是操作码的值,后面的字节是操作数或参数。

我可以理解 1A 是 4 的十六进制表示,所以我是否理解正确的十六进制值被保存用于引用它的值或者它意味着不同的东西?

1A在这种情况下是ldc.i4.4操作码的值。该操作码是一条ldc.i4 4指令的快捷方式,它会导致完全相同的行为,但长度为 5 字节,操作码为 1 字节,参数为 4 字节。这些快捷方式适用于从 -1 到 8 的 int 值,因为它们经常被使用,因此可以减小方法体的大小。

现在应该清楚您的浮点指令是如何形成的。23是操作码,22参数是IEEE 754编码的浮点数。

于 2016-01-21T12:41:21.763 回答
7

不同的 IL 指令有不同的字节码。ldc.i4.4 是 0x1A,ldc.r8 是 0x23,ldc.r4 是 0x22。反编译器将这些字节值转换为它们对应的 IL 指令字符串,帮助您阅读代码。

ldc.r4 和 ldc.r8 指令有额外的字节来编码参数,分别是一个 4 字节的浮点数和一个 8 字节的双精度数。反编译器显示值的字节表示。A4-70-45-41 与您从 BitConverter.GetBytes(12.34f) 获得的字节相同,只需在一个小程序中尝试自己查看即可。

ldc.i4.4 指令有点特殊,它是一个专用指令,它压入 4 并且没有参数。-1 到 9 的整数值有这样的指令,它们在程序中很常见。给他们专门的指令可以保持 IL 紧凑。

于 2016-01-21T12:38:58.423 回答
3

“AE 47 E1 7A 14 AE 28 40”是双精度值的实际字节表示的十六进制表示12.34

为了证明

double d = 12.34;   
var bytes = BitConverter.GetBytes(d);
StringBuilder sb = new StringBuilder();
foreach (var b in bytes)
{
    sb.Append(b.ToString("X2"));
}
sb.Dump();

印刷

AE47E17A14AE2840

23 是 Opcode 值的十六进制表示,ldc.r822 表示ldc.r4等。

资源

于 2016-01-21T12:40:32.127 回答