当将一个int32
加到一个64位的native int
时,CLR是进行符号扩展还是零扩展32位整数?最重要的是:它基于什么信息做出这个选择?
我正在编写一个.NET编译器,并已经彻底阅读了ECMA规范,但找不到答案。
CLI仅支持在其操作中对其评估堆栈上存储的值的子集执行此类操作:
int32
、int64
和native int
。
-- ECMA 335,第I12.1节:支持的数据类型
由于评估堆栈上的值没有有关其有符号性的信息,因此涉及操作数的符号的指令有两个变体:一个用于有符号整数,一个用于无符号整数。add
、sub
和mul
指令(那些不检查溢出的指令)只要操作数大小相同就不需要关心操作数的符号,因此只有一个变体。 然而,操作数并不总是相同的大小...
ECMA 335,第III1.5节:操作数类型表指出可以将int32
和native int
相加、相减、相乘和相除。结果再次是一个native int
。在64位系统上,native int
宽度为64位。
ldc.i4.0 // Load int32 0
conv.i // Convert to (64-bit) native int
ldc.i4.m1 // Load int32 -1
add // Add native int 0 and int32 0xFFFFFFFF together
那么这里会得到什么结果?需要注意的是,根据规范,运行时不需要跟踪堆栈上值的确切类型或带符号性:它只知道 int32
、int64
和 native int
(以及其他些许与本处无关的类型)。
我想象 IntPtr
和 UIntPtr
的算术运算,由于它们在内部表示为 native ints,也会使用这种类型的加法。然而,ILSpy 显示在 C# 中将 IntPtr
和 Int32
相加调用了 IntPtr
类的重载 + 操作符,该操作符仅接受带符号的 Int32
参数。
使用 CIL 直接执行它(使用 add
指令)还表明整数被解释为带符号数。它也应该已经在 Mono 中实现了,但我找不到任何参考来支持我的发现。