本机大小的整数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
标识符 nint
和 nuint
是表示本机签名和无符号整数类型的新上下文关键字。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.IntPtr
, System.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
常数表达式的类型可以是 nint
或 nuint
。Constant 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.MaxValue
。nint
constants are in the range [ int.MinValue
, int.MaxValue
].
nuint
常量处于 [ uint.MinValue
,] 范围内 uint.MaxValue
。nuint
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 { +
, -
, *
, /
, %
, ==
, !=
, <
, <=
, >
, >=
, &
, |
, ^
, <<
, >>
}.
不管编译器平台如何,都将用 Int32
和 UInt32
操作数(而不是本机整数)来计算常量折叠运算。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
UIntPtr
。There 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 fromA
toB
; - 如果存在从到的显式转换,则为显式可为 null 的转换
A
B
;an explicit nullable conversion if there is an explicit conversion fromA
toB
; - 否则无效。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 fromA
toB
; - 否则无效。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 fromA
toB
; - 如果从到的隐式或显式数字转换,则为显式可为 null 的转换
A
B
;an explicit nullable conversion if there is an implicit or explicit numeric conversion fromA
toB
; - 否则无效。otherwise invalid.
运算符Operators
预定义运算符如下所示。The predefined operators are as follows.
如果至少有一个操作数的类型为 nint
或 nuint
,则在重载解析过程中,将根据隐式转换的常规规则考虑这些运算符。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
转换和运算符由编译器合成并且不属于基础 IntPtr
和 UIntPtr
类型。The conversions and operators are synthesized by the compiler and are not part of the underlying IntPtr
and UIntPtr
types.
因此,这些转换和运算符在的运行时联编程序中不可用 dynamic
。As 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
或中 nuint
:The 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
和中 nuint
。The 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
nint
和 System.IntPtr
、和 nuint
System.UIntPtr
都被视为等效于重写、隐藏和实现。nint
and System.IntPtr
, and nuint
and System.UIntPtr
, are considered equivalent for overriding, hiding, and implementing.
重载不能单独不同于 nint
和 System.IntPtr
、和 nuint
System.UIntPtr
。Overloads cannot differ by nint
and System.IntPtr
, and nuint
and System.UIntPtr
, alone.
重写和实现可单独不同于 nint
System.IntPtr
、、或 nuint
System.UIntPtr
。Overrides and implementations may differ by nint
and System.IntPtr
, or nuint
and System.UIntPtr
, alone.
方法隐藏了不同于 nint
System.IntPtr
、或和的其他 nuint
方法 System.UIntPtr
。Methods 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
}
nint
和 nuint
可用作 enum
基类型。nint
and nuint
can be used as an enum
base type.
enum E : nint // ok
{
}
对于类型 nint
、和的和,读取和写入是原子的 nuint
enum
nint
nuint
。Reads and writes are atomic for types nint
, nuint
, and enum
with base type nint
or nuint
.
可以将字段标记 volatile
为类型 nint
和 nuint
。Fields may be marked volatile
for types nint
and nuint
.
ECMA-334 15.5.4 不包括 enum
基类型 System.IntPtr
或 System.UIntPtr
。ECMA-334 15.5.4 does not include enum
with base type System.IntPtr
or System.UIntPtr
however.
default(nint)
和与 new nint()
等效 (nint)0
。default(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.Size
。sizeof(nint)
is implemented as sizeof(IntPtr)
rather than IntPtr.Size
.
编译器诊断,适用于涉及或报告的类型引用, nint
nuint
nint
nuint
而不是或 IntPtr
UIntPtr
。Compiler diagnostics for type references involving nint
or nuint
report nint
or nuint
rather than IntPtr
or UIntPtr
.
元数据Metadata
nint
和 nuint
在元数据中表示为 System.IntPtr
和 System.UIntPtr
。nint
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.NativeInt
和 System.NativeUInt
。An 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
- https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-05-26.md
- https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-06-13.md
- https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-07-05.md#native-int-and-intptr-operators
- https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-10-23.md
- https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-03-25.md