当我们声明变量int
时,例如:
int i = 4;
生成以下IL:
IL_0001: /* 1A | */ ldc.i4.4
我可以理解1A是16的十六进制表示,所以我理解正确的十六进制值被保存用来指代它的值或它意味着不同的东西吗?
当我声明一个双变量时:
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
是什么?
答案 0 :(得分:8)
我认为了解ildasm告诉你什么很重要。管道字符前面的字节是操作码的值,后面的字节是操作数或参数。
在这种情况下,我可以理解1A是16的十六进制表示,所以我理解正确的十六进制值被保存用于指代它的值或它意味着不同的东西吗?
1A
是ldc.i4.4
操作码的值。此操作码是ldc.i4 4
指令的快捷方式,它将导致绝对相同的行为,但将是5个字节长,1个字节操作码和4个字节参数。这些快捷方式对于从-1到8的int值存在,因为它们经常被使用,因此可以减小方法体的大小。
现在应该清楚浮点指令是如何形成的。 23
和22
是操作码,参数是IEEE 754
编码的浮点数。
答案 1 :(得分: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紧凑。
答案 2 :(得分:3)
" AE 47 E1 7A 14 AE 28 40"是double值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是操作码值ldc.r8
的十六进制表示,而ldc.r4
等为22。