float 和 double 如何在 IL 中工作

How float and double work in IL

当我们声明一个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 是什么?

不同的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 保持紧凑。

"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 是 Opcode 值的十六进制表示 ldc.r8 和 22 表示 ldc.r4

Source

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

I can understand that 1A is the hexadecimal representation of 4, so am I understanding right that hexadecimal value is saved used to refer to value of it or it means something different?

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

现在应该清楚你的浮点指令是如何构成的了。 2322 是操作码,参数是 IEEE 754 编码的浮点数。