本机大小的整数Native-sized integers

总结Summary

本机大小的有符号和无符号整数类型的语言支持。Language support for a native-sized signed and unsigned integer types.

动机适用于互操作方案和低级别库。The motivation is for interop scenarios and for low-level libraries.

设计Design

标识符 nintnuint 是表示本机签名和无符号整数类型的新上下文关键字。The identifiers nint and nuint are new contextual keywords that represent native signed and unsigned integer types. 仅当名称查找在该程序位置找不到可行的结果时,才将标识符视为关键字。The identifiers are only treated as keywords when name lookup does not find a viable result at that program location.

nint x = 3;
string y = nameof(nuint);
_ = nint.Equals(x, 3);

类型 nint 和由 nuint 基础类型表示 System.IntPtrSystem.UIntPtr 编译器将这些类型的其他转换和操作呈现为本机整数。The types nint and nuint are represented by the underlying types System.IntPtr and System.UIntPtr with compiler surfacing additional conversions and operations for those types as native ints.

常量Constants

常数表达式的类型可以是 nintnuintConstant expressions may be of type nint or nuint. 本机 int 文本没有直接的语法。There is no direct syntax for native int literals. 可以改为使用其他整数常数值的隐式或显式转换: const nint i = (nint)42;Implicit or explicit casts of other integral constant values can be used instead: const nint i = (nint)42;.

nint 常量处于 [ int.MinValue ,] 范围内 int.MaxValuenint constants are in the range [ int.MinValue, int.MaxValue ].

nuint 常量处于 [ uint.MinValue ,] 范围内 uint.MaxValuenuint constants are in the range [ uint.MinValue, uint.MaxValue ].

MinValue MaxValue 或上没有字段或, nint 因为不 nuint nuint.MinValue 能将这些值作为常量发出。There are no MinValue or MaxValue fields on nint or nuint because, other than nuint.MinValue, those values cannot be emitted as constants.

所有一元运算符 { +-~ } 和二元运算符 { +-* / % == != < <= > >= & | ^ << >> ,,,,,,,,,,,,,,则支持常量折叠。Constant folding is supported for all unary operators { +, -, ~ } and binary operators { +, -, *, /, %, ==, !=, <, <=, >, >=, &, |, ^, <<, >> }. 不管编译器平台如何,都将用 Int32UInt32 操作数(而不是本机整数)来计算常量折叠运算。Constant folding operations are evaluated with Int32 and UInt32 operands rather than native ints for consistent behavior regardless of compiler platform. 如果该操作导致32位中的常量值,则会在编译时执行常量折叠。If the operation results in a constant value in 32-bits, constant folding is performed at compile-time. 否则,将在运行时执行该操作,而不会将其视为常数。Otherwise the operation is executed at runtime and not considered a constant.

转换Conversions

在和之间存在一个标识转换,在和之间存在一个恒等转换 nint IntPtr nuint UIntPtrThere is an identity conversion between nint and IntPtr, and between nuint and UIntPtr. 仅有不同于本机 int 和基础类型的复合类型之间存在标识转换:数组、 Nullable<> 、构造类型和元组。There is an identity conversion between compound types that differ by native ints and underlying types only: arrays, Nullable<>, constructed types, and tuples.

下表介绍了特殊类型之间的转换。The tables below cover the conversions between special types. (每个转换的 IL 包括和上下文的变量( unchecked checked 如果不同)。 ) (The IL for each conversion includes the variants for unchecked and checked contexts if different.)

操作数Operand 目标Target 转换Conversion ILIL
object nint 取消装箱Unboxing unbox
void* nint PointerToVoidPointerToVoid conv.i
sbyte nint ImplicitNumericImplicitNumeric conv.i
byte nint ImplicitNumericImplicitNumeric conv.u
short nint ImplicitNumericImplicitNumeric conv.i
ushort nint ImplicitNumericImplicitNumeric conv.u
int nint ImplicitNumericImplicitNumeric conv.i
uint nint ExplicitNumericExplicitNumeric conv.u / conv.ovf.u
long nint ExplicitNumericExplicitNumeric conv.i / conv.ovf.i
ulong nint ExplicitNumericExplicitNumeric conv.i / conv.ovf.i
char nint ImplicitNumericImplicitNumeric conv.i
float nint ExplicitNumericExplicitNumeric conv.i / conv.ovf.i
double nint ExplicitNumericExplicitNumeric conv.i / conv.ovf.i
decimal nint ExplicitNumericExplicitNumeric long decimal.op_Explicit(decimal) conv.i / ... conv.ovf.i
IntPtr nint 标识Identity
UIntPtr nint None
object nuint 取消装箱Unboxing unbox
void* nuint PointerToVoidPointerToVoid conv.u
sbyte nuint ExplicitNumericExplicitNumeric conv.u / conv.ovf.u
byte nuint ImplicitNumericImplicitNumeric conv.u
short nuint ExplicitNumericExplicitNumeric conv.u / conv.ovf.u
ushort nuint ImplicitNumericImplicitNumeric conv.u
int nuint ExplicitNumericExplicitNumeric conv.u / conv.ovf.u
uint nuint ImplicitNumericImplicitNumeric conv.u
long nuint ExplicitNumericExplicitNumeric conv.u / conv.ovf.u
ulong nuint ExplicitNumericExplicitNumeric conv.u / conv.ovf.u
char nuint ImplicitNumericImplicitNumeric conv.u
float nuint ExplicitNumericExplicitNumeric conv.u / conv.ovf.u
double nuint ExplicitNumericExplicitNumeric conv.u / conv.ovf.u
decimal nuint ExplicitNumericExplicitNumeric ulong decimal.op_Explicit(decimal) conv.u / ... conv.ovf.u.un
IntPtr nuint None
UIntPtr nuint 标识Identity
枚举Enumeration nint ExplicitEnumerationExplicitEnumeration
枚举Enumeration nuint ExplicitEnumerationExplicitEnumeration
操作数Operand 目标Target 转换Conversion ILIL
nint object 装箱Boxing box
nint void* PointerToVoidPointerToVoid conv.i
nint nuint ExplicitNumericExplicitNumeric conv.u / conv.ovf.u
nint sbyte ExplicitNumericExplicitNumeric conv.i1 / conv.ovf.i1
nint byte ExplicitNumericExplicitNumeric conv.u1 / conv.ovf.u1
nint short ExplicitNumericExplicitNumeric conv.i2 / conv.ovf.i2
nint ushort ExplicitNumericExplicitNumeric conv.u2 / conv.ovf.u2
nint int ExplicitNumericExplicitNumeric conv.i4 / conv.ovf.i4
nint uint ExplicitNumericExplicitNumeric conv.u4 / conv.ovf.u4
nint long ImplicitNumericImplicitNumeric conv.i8 / conv.ovf.i8
nint ulong ExplicitNumericExplicitNumeric conv.i8 / conv.ovf.i8
nint char ExplicitNumericExplicitNumeric conv.u2 / conv.ovf.u2
nint float ImplicitNumericImplicitNumeric conv.r4
nint double ImplicitNumericImplicitNumeric conv.r8
nint decimal ImplicitNumericImplicitNumeric conv.i8 decimal decimal.op_Implicit(long)
nint IntPtr 标识Identity
nint UIntPtr None
nint 枚举Enumeration ExplicitEnumerationExplicitEnumeration
nuint object 装箱Boxing box
nuint void* PointerToVoidPointerToVoid conv.u
nuint nint ExplicitNumericExplicitNumeric conv.i / conv.ovf.i
nuint sbyte ExplicitNumericExplicitNumeric conv.i1 / conv.ovf.i1
nuint byte ExplicitNumericExplicitNumeric conv.u1 / conv.ovf.u1
nuint short ExplicitNumericExplicitNumeric conv.i2 / conv.ovf.i2
nuint ushort ExplicitNumericExplicitNumeric conv.u2 / conv.ovf.u2
nuint int ExplicitNumericExplicitNumeric conv.i4 / conv.ovf.i4
nuint uint ExplicitNumericExplicitNumeric conv.u4 / conv.ovf.u4
nuint long ExplicitNumericExplicitNumeric conv.i8 / conv.ovf.i8
nuint ulong ImplicitNumericImplicitNumeric conv.u8 / conv.ovf.u8
nuint char ExplicitNumericExplicitNumeric conv.u2 / conv.ovf.u2.un
nuint float ImplicitNumericImplicitNumeric conv.r.un conv.r4
nuint double ImplicitNumericImplicitNumeric conv.r.un conv.r8
nuint decimal ImplicitNumericImplicitNumeric conv.u8 decimal decimal.op_Implicit(ulong)
nuint IntPtr None
nuint UIntPtr 标识Identity
nuint 枚举Enumeration ExplicitEnumerationExplicitEnumeration

从到的转换 A Nullable<B> 为:Conversion from A to Nullable<B> is:

  • 如果有标识转换或从到的隐式转换,则为隐式可为 null 的转换 A B ;an implicit nullable conversion if there is an identity conversion or implicit conversion from A to B;
  • 如果存在从到的显式转换,则为显式可为 null 的转换 A B ;an explicit nullable conversion if there is an explicit conversion from A to B;
  • 否则无效。otherwise invalid.

从到的转换 Nullable<A> B 为:Conversion from Nullable<A> to B is:

  • 如果有标识转换或从到的隐式或显式数字转换,则为显式可为 null 的转换 A B ;an explicit nullable conversion if there is an identity conversion or implicit or explicit numeric conversion from A to B;
  • 否则无效。otherwise invalid.

从到的转换 Nullable<A> Nullable<B> 为:Conversion from Nullable<A> to Nullable<B> is:

  • 如果存在从到的标识转换,则为标识转换 A B ;an identity conversion if there is an identity conversion from A to B;
  • 如果从到的隐式或显式数字转换,则为显式可为 null 的转换 A B ;an explicit nullable conversion if there is an implicit or explicit numeric conversion from A to B;
  • 否则无效。otherwise invalid.

运算符Operators

预定义运算符如下所示。The predefined operators are as follows. 如果至少有一个操作数的类型为 nintnuint,则在重载解析过程中,将根据隐式转换的常规规则考虑这些运算符。These operators are considered during overload resolution based on normal rules for implicit conversions if at least one of the operands is of type nint or nuint.

(每个运算符的 IL 包含和上下文的变量( unchecked checked 如果不同)。 ) (The IL for each operator includes the variants for unchecked and checked contexts if different.)

一元Unary 运算符签名Operator Signature ILIL
+ nint operator +(nint value) nop
+ nuint operator +(nuint value) nop
- nint operator -(nint value) neg
~ nint operator ~(nint value) not
~ nuint operator ~(nuint value) not
二进制Binary 运算符签名Operator Signature ILIL
+ nint operator +(nint left, nint right) add / add.ovf
+ nuint operator +(nuint left, nuint right) add / add.ovf.un
- nint operator -(nint left, nint right) sub / sub.ovf
- nuint operator -(nuint left, nuint right) sub / sub.ovf.un
* nint operator *(nint left, nint right) mul / mul.ovf
* nuint operator *(nuint left, nuint right) mul / mul.ovf.un
/ nint operator /(nint left, nint right) div
/ nuint operator /(nuint left, nuint right) div.un
% nint operator %(nint left, nint right) rem
% nuint operator %(nuint left, nuint right) rem.un
== bool operator ==(nint left, nint right) beq / ceq
== bool operator ==(nuint left, nuint right) beq / ceq
!= bool operator !=(nint left, nint right) bne
!= bool operator !=(nuint left, nuint right) bne
< bool operator <(nint left, nint right) blt / clt
< bool operator <(nuint left, nuint right) blt.un / clt.un
<= bool operator <=(nint left, nint right) ble
<= bool operator <=(nuint left, nuint right) ble.un
> bool operator >(nint left, nint right) bgt / cgt
> bool operator >(nuint left, nuint right) bgt.un / cgt.un
>= bool operator >=(nint left, nint right) bge
>= bool operator >=(nuint left, nuint right) bge.un
& nint operator &(nint left, nint right) and
& nuint operator &(nuint left, nuint right) and
| nint operator |(nint left, nint right) or
| nuint operator |(nuint left, nuint right) or
^ nint operator ^(nint left, nint right) xor
^ nuint operator ^(nuint left, nuint right) xor
<< nint operator <<(nint left, int right) shl
<< nuint operator <<(nuint left, int right) shl
>> nint operator >>(nint left, int right) shr
>> nuint operator >>(nuint left, int right) shr.un

对于某些二元运算符,IL 运算符支持其他操作数类型 (请参阅 ECMA-335 III. 1.5 操作数类型表) 。For some binary operators, the IL operators support additional operand types (see ECMA-335 III.1.5 Operand type table). 但对于简单起见,c # 支持的操作数类型集是有限的,并且与语言中的现有运算符保持一致。But the set of operand types supported by C# is limited for simplicity and for consistency with existing operators in the language.

支持参数和返回类型为和的运算符的提升版本 nint? nuint?Lifted versions of the operators, where the arguments and return types are nint? and nuint?, are supported.

与具有 x op= y x y 预定义运算符的其他基元类型相同,或为本机 int 的复合赋值运算遵循相同的规则。Compound assignment operations x op= y where x or y are native ints follow the same rules as with other primitive types with pre-defined operators. 具体而言,表达式绑定为, x = (T)(x op y) 其中 T 是的类型 x ,其中 x 只计算一次。Specifically the expression is bound as x = (T)(x op y) where T is the type of x and where x is only evaluated once.

如果为4,则移位运算符应将位数屏蔽为 shift + 5 位 sizeof(nint) ,如果为8,则为6位 sizeof(nint)The shift operators should mask the number of bits to shift - to 5 bits if sizeof(nint) is 4, and to 6 bits if sizeof(nint) is 8. (参见 c # spec) 中的 移位运算符(see shift operators in C# spec).

使用早期的语言版本进行编译时,c # 9 编译器将报告与预定义的本机整数运算符绑定的错误,但允许对本机整数使用预定义的转换。The C#9 compiler will report errors binding to predefined native integer operators when compiling with an earlier language version, but will allow use of predefined conversions to and from native integers.

csc -langversion:9 -t:library A.cs

public class A
{
    public static nint F;
}

csc -langversion:8 -r:A.dll B.cs

class B : A
{
    static void Main()
    {
        F = F + 1; // error: nint operator+ not available with -langversion:8
        F = (System.IntPtr)F + 1; // ok
    }
}

动态Dynamic

转换和运算符由编译器合成并且不属于基础 IntPtrUIntPtr 类型。The conversions and operators are synthesized by the compiler and are not part of the underlying IntPtr and UIntPtr types. 因此,这些转换和运算符在的运行时联编程序中不可用 dynamicAs a result those conversions and operators are not available from the runtime binder for dynamic.

nint x = 2;
nint y = x + x; // ok
dynamic d = x;
nint z = d + x; // RuntimeBinderException: '+' cannot be applied 'System.IntPtr' and 'System.IntPtr'

类型成员Type members

或的唯一构造函数是不带 nint nuint 参数的构造函数。The only constructor for nint or nuint is the parameter-less constructor.

和的以下成员 System.IntPtr System.UIntPtr 被显式排除nint 或中 nuintThe following members of System.IntPtr and System.UIntPtr are explicitly excluded from nint or nuint:

// constructors
// arithmetic operators
// implicit and explicit conversions
public static readonly IntPtr Zero; // use 0 instead
public static int Size { get; }     // use sizeof() instead
public static IntPtr Add(IntPtr pointer, int offset);
public static IntPtr Subtract(IntPtr pointer, int offset);
public int ToInt32();
public long ToInt64();
public void* ToPointer();

和的其余成员 System.IntPtr System.UIntPtr 将隐式包含nint 和中 nuintThe remaining members of System.IntPtr and System.UIntPtr are implicitly included in nint and nuint. 对于 .NET Framework 4.7.2:For .NET Framework 4.7.2:

public override bool Equals(object obj);
public override int GetHashCode();
public override string ToString();
public string ToString(string format);

和实现的 System.IntPtr 接口 System.UIntPtr 将隐式包含nint 和中 nuint ,其中出现的基础类型由相应的本机整数类型替换。Interfaces implemented by System.IntPtr and System.UIntPtr are implicitly included in nint and nuint, with occurrences of the underlying types replaced by the corresponding native integer types. 例如,如果 IntPtr 实现 ISerializable, IEquatable<IntPtr>, IComparable<IntPtr> ,则 nint 实现 ISerializable, IEquatable<nint>, IComparable<nint>For instance if IntPtr implements ISerializable, IEquatable<IntPtr>, IComparable<IntPtr>, then nint implements ISerializable, IEquatable<nint>, IComparable<nint>.

重写、隐藏和实现Overriding, hiding, and implementing

nintSystem.IntPtr 、和 nuint System.UIntPtr 都被视为等效于重写、隐藏和实现。nint and System.IntPtr, and nuint and System.UIntPtr, are considered equivalent for overriding, hiding, and implementing.

重载不能单独不同于 nintSystem.IntPtr 、和 nuint System.UIntPtrOverloads cannot differ by nint and System.IntPtr, and nuint and System.UIntPtr, alone. 重写和实现可单独不同于 nint System.IntPtr 、、或 nuint System.UIntPtrOverrides and implementations may differ by nint and System.IntPtr, or nuint and System.UIntPtr, alone. 方法隐藏了不同于 nint System.IntPtr 、或和的其他 nuint 方法 System.UIntPtrMethods hide other methods that differ by nint and System.IntPtr, or nuint and System.UIntPtr, alone.

杂项Miscellaneous

nint 用作 nuint 数组索引的表达式将在不进行转换的情况下发出。nint and nuint expressions used as array indices are emitted without conversion.

static object GetItem(object[] array, nint index)
{
    return array[index]; // ok
}

nintnuint 可用作 enum 基类型。nint and nuint can be used as an enum base type.

enum E : nint // ok
{
}

对于类型 nint 、和的和,读取和写入是原子的 nuint enum nint nuintReads and writes are atomic for types nint, nuint, and enum with base type nint or nuint.

可以将字段标记 volatile 为类型 nintnuintFields may be marked volatile for types nint and nuint. ECMA-334 15.5.4 不包括 enum 基类型 System.IntPtrSystem.UIntPtrECMA-334 15.5.4 does not include enum with base type System.IntPtr or System.UIntPtr however.

default(nint) 和与 new nint() 等效 (nint)0default(nint) and new nint() are equivalent to (nint)0.

typeof(nint)typeof(IntPtr)typeof(nint) is typeof(IntPtr).

sizeof(nint) 支持,但要求在不安全的上下文中进行编译 (sizeof(IntPtr)) 。sizeof(nint) is supported but requires compiling in an unsafe context (as does sizeof(IntPtr)). 该值不是编译时常量。The value is not a compile-time constant. sizeof(nint) 实现为 sizeof(IntPtr) 而不是 IntPtr.Sizesizeof(nint) is implemented as sizeof(IntPtr) rather than IntPtr.Size.

编译器诊断,适用于涉及或报告的类型引用, nint nuint nint nuint 而不是或 IntPtr UIntPtrCompiler diagnostics for type references involving nint or nuint report nint or nuint rather than IntPtr or UIntPtr.

元数据Metadata

nintnuint 在元数据中表示为 System.IntPtrSystem.UIntPtrnint and nuint are represented in metadata as System.IntPtr and System.UIntPtr.

包含或的类型引用, nint nuint System.Runtime.CompilerServices.NativeIntegerAttribute 用于指示类型引用的哪些部分是本机整数。Type references that include nint or nuint are emitted with a System.Runtime.CompilerServices.NativeIntegerAttribute to indicate which parts of the type reference are native ints.

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(
        AttributeTargets.Class |
        AttributeTargets.Event |
        AttributeTargets.Field |
        AttributeTargets.GenericParameter |
        AttributeTargets.Parameter |
        AttributeTargets.Property |
        AttributeTargets.ReturnValue,
        AllowMultiple = false,
        Inherited = false)]
    public sealed class NativeIntegerAttribute : Attribute
    {
        public NativeIntegerAttribute()
        {
            TransformFlags = new[] { true };
        }
        public NativeIntegerAttribute(bool[] flags)
        {
            TransformFlags = flags;
        }
        public readonly bool[] TransformFlags;
    }
}

NativeIntegerAttribute NativeIntegerAttribute.md中介绍了的类型引用编码。The encoding of type references with NativeIntegerAttribute is covered in NativeIntegerAttribute.md.

备选方法Alternatives

上述 "类型擦除" 方法的替代方法是引入新的类型: System.NativeIntSystem.NativeUIntAn alternative to the "type erasure" approach above is to introduce new types: System.NativeInt and System.NativeUInt.

public readonly struct NativeInt
{
    public IntPtr Value;
}

Distinct 类型允许重载不同于 IntPtr ,并允许不同的分析和 ToString()Distinct types would allow overloading distinct from IntPtr and would allow distinct parsing and ToString(). 但是,CLR 可以更好地处理这些类型,这违背了功能效率的主要目的。But there would be more work for the CLR to handle these types efficiently which defeats the primary purpose of the feature - efficiency. 与使用现有本机 int 代码的互操作性 IntPtr 更难。And interop with existing native int code that uses IntPtr would be more difficult.

另一种替代方法是在框架中添加更多本机 int 支持, IntPtr 但没有任何特定的编译器支持。Another alternative is to add more native int support for IntPtr in the framework but without any specific compiler support. 编译器将自动支持任何新的转换和算术运算。Any new conversions and arithmetic operations would be supported by the compiler automatically. 但该语言不会提供关键字、常量或 checked 操作。But the language would not provide keywords, constants, or checked operations.

设计会议Design meetings