次の方法で共有


数値 IntPtr

メモ

この記事は機能仕様についてです。 仕様は、機能の設計ドキュメントとして使用できます。 これには、提案された仕様の変更および機能の設計と開発時に必要な情報が含まれます。 これらの記事は、提案された仕様の変更が決定され、現在の ECMA 仕様に組み込まれるまで公開されます。

機能の仕様と行われた実装では、いくつかの違いがあることがあります。 これらの違いは、関連する言語設計ミーティング (LDM) メモに取り上げられています。

機能仕様を C# 言語標準に導入するプロセスの詳細については、仕様に関する記事を参照してください。

チャンピオンの課題: https://github.com/dotnet/csharplang/issues/6065

まとめ

これは、最初のネイティブ整数機能 (仕様) のリビジョンであり、nint/nuint 型は基になる型 System.IntPtr/System.UIntPtr とは異なっていました。 つまり、nint/nuint は、System.Int32 に関連して int のために行うように、System.IntPtr/System.UIntPtr をエイリアス化する単純な型として扱います。 System.Runtime.CompilerServices.RuntimeFeature.NumericIntPtr ランタイム機能フラグによって、この新しい動作がトリガーされます。

設計

8.3.5 単純型

C# には、単純型と呼ばれる定義済みの struct 型のセットが用意されています。 単純型はキーワードを使用して識別されますが、次の表に示すように、これらのキーワードは System 名前空間の定義済み struct 型の単なるエイリアスです。

キーワード エイリアス化された型
sbyte System.SByte
byte System.Byte
short System.Int16
ushort System.UInt16
int System.Int32
uint System.UInt32
nint System.IntPtr
nuint System.UIntPtr
long System.Int64
ulong System.UInt64
char System.Char
float System.Single
double System.Double
bool System.Boolean
decimal System.Decimal

[...]

8.3.6 整数型

C# では、sbytebyteshortushortintuintnintnuintlongulongchar7 つの整数型がサポートされています。 [...]

8.8 アンマネージ型

つまり、unmanaged_type は次のいずれかになります。

  • sbyte, byte, short, ushort, int, uint, ,nint, nuint,, long, ulong, char, float, double, decimal, bool.
  • すべての enum_type
  • 構築型以外の、unmanaged_typeのフィールドのみを含む、ユーザー定義のすべての struct_type
  • 安全でないコードでは、任意の ポインター型を使用することができます。

10.2.3 暗黙の数値変換

暗黙の数値変換は次のとおりです。

  • sbyte から shortintnintlongfloatdouble、または decimal
  • byte から shortushortintuintnintnuintlongulongfloatdouble または decimal
  • short から intnintlongfloatdouble または decimal
  • ushort から intuintnintnuintlongulongfloatdouble、または decimal
  • int から nintlongfloatdouble、または decimal
  • uint から nuintlongulongfloatdouble または decimal
  • nint から longfloatdouble、または decimalまで。
  • nuint から ulongfloatdouble、または decimalまで。
  • long から floatdouble、または decimal
  • ulong から floatdouble、または decimal
  • char から ushortintuintnintnuintlongulongfloatdouble、または decimal
  • float から double

[...]

10.2.11 暗黙的な定数式の変換

暗黙的な定数式の変換では、次の変換が可能です。

  • int 型の constant_expression は、constant_expressionの値が変換後の型の範囲内にある場合、型 sbytebyteshortushortuintnintnuintまたは ulong に変換できます。 [...]

10.3.2 明示的な数値変換

明示的な数値変換とは、暗黙的な数値変換がまだ存在しない別の numeric_type への numeric_type からの変換です。

  • sbyte から byteushortuintnuintulong または char
  • byte から sbyte または char
  • short から sbytebyteushortuintnuintulong、または char
  • ushort から sbytebyteshort または char
  • int から sbytebyteshortushortuintnuintulong または char
  • uint から sbytebyteshortushortintnint、または char
  • long から sbytebyteshortushortintuintnintnuintulong、または char
  • nint から sbytebyteshortushortintuintnuintulong または char
  • nuint から sbytebyteshortushortintuintnintlong または char
  • ulong から sbytebyteshortushortintuintnintnuintlong、または char
  • char から sbytebyte、または short
  • float から sbytebyteshortushortintuintnintnuintlongulongchar または decimal
  • double から sbytebyteshortushortintuintnintnuintlongulongcharfloat または decimal
  • decimal から sbytebyteshortushortintuintnintnuintlongulongcharfloat または double

[...]

10.3.3 明示的な列挙変換

明示的な列挙変換は次のとおりです。

  • sbytebyteshortushortintuintnintnuintlongulongcharfloatdouble、または decimal から任意の enum_typeに。
  • 任意の enum_type から sbytebyteshortushortintuintnintnuintlongulongcharfloatdouble、または decimal
  • 任意の enum_type から他の任意の enum_type

12.6.4.7 コンバージョンターゲットの向上

の 2 種類の場合、次のいずれかが該当する場合に、 よりも 優れた変換ターゲットです。

  • T₁ から T₂ への暗黙的な変換が存在し、 T₂ から T₁ への暗黙的な変換は存在しません
  • T₁Task<S₁> であり、T₂Task<S₂> であり、S₁S₂ よりも優れた変換ターゲットです
  • T₁S₁ または S₁? で、 S₁ は符号付き整数型、 T₂S₂ または S₂? で、 S₂ は符号なし整数型です。 具体的には: [...]

12.8.12 要素アクセス

[...] argument_list 内の式の数は、 array_type のランクと同じである必要があります。各式は、int uintnint nuintlong、または ulong, の型であるか、暗黙的にこれらの型の 1 つ以上に変換可能である必要があります。

11.8.12.2 配列へのアクセス

[...] argument_list 内の式の数は、 array_type のランクと同じである必要があります。各式は、int uintnint nuintlong、または ulong, の型であるか、暗黙的にこれらの型の 1 つ以上に変換可能である必要があります。

形[...] 式 P[A] (P は、array_typeprimary_no_array_creation_expression で、A は、argument_list) の配列アクセスの実行時処理は、次の手順で構成されています。[...]

  • argument_list のインデックス式は、左から右の順に評価されます。 各インデックス式の評価の後、暗黙的な変換を次のいずれかの型に変換します。intuintnintnuintlongulong。 暗黙的な変換が存在するこのリストの最初の型が選択されます。 [...]

12.8.16 後置インクリメント演算子と後置デクリメント演算子

単項演算子のオーバーロード解決は、特定の演算子の実装を選択するために適用されます。 定義済みの ++ 演算子と -- 演算子は、sbytebyteshortushortintuintnintnuintlongulongcharfloatdoubledecimal、および任意の列挙型に対して存在します。

12.9.2 単項プラス演算子

定義済みの単項プラス演算子は次のとおりです。

...
nint operator +(nint x);
nuint operator +(nuint x);

12.9.3 単項マイナス演算子

定義済みの単項マイナス演算子は次のとおりです。

  • 整数否定:

    ...
    nint operator –(nint x);
    

12.8.16 後置インクリメント演算子と後置デクリメント演算子

定義済みの ++ 演算子と -- 演算子は、sbytebyteshortushortintuintnintnuintlongulongcharfloatdoubledecimal、および任意の列挙型に対して存在します。

11.7.19 既定値式

さらに、default_value_expression は、sbytebyteshortushortintuintnintnuintlongulongcharfloatdoubledecimalbool,、または任意の列挙型のいずれかの値型の場合、定数式になります。

12.9.5 ビットごとの補数演算子

定義済みのビットごとの補数演算子は次のとおりです。

...
nint operator ~(nint x);
nuint operator ~(nuint x);

12.9.6 前置インクリメント演算子と前置デクリメント演算子

定義済みの ++ 演算子と -- 演算子は、sbytebyteshortushortintuintnintnuintlongulongcharfloatdoubledecimal、および任意の列挙型に対して存在します。

12.10 算術演算子

12.10.2 乗算演算子

定義済みの乗算演算子を次に示します。 演算子はすべて、xy の積を計算します。

  • 整数乗算:

    ...
    nint operator *(nint x, nint y);
    nuint operator *(nuint x, nuint y);
    

12.10.3 除算演算子

定義済みの除算演算子を次に示します。 演算子はどれも、xyの商を計算します。

  • 整数の除算:

    ...
    nint operator /(nint x, nint y);
    nuint operator /(nuint x, nuint y);
    

12.10.4 剰余演算子

定義済みの剰余演算子を次に示します。 演算子はすべて、xy の間の除算の剰余を計算します。

  • 整数の剰余:

    ...
    nint operator %(nint x, nint y);
    nuint operator %(nuint x, nuint y);
    

12.10.5 加算演算子

  • 整数の加算:

    ...
    nint operator +(nint x, nint y);
    nuint operator +(nuint x, nuint y);
    

12.10.6 減算演算子

  • 整数の減算:

    ...
    nint operator –(nint x, nint y);
    nuint operator –(nuint x, nuint y);
    

12.11 シフト演算子

定義済みのシフト演算子を次に示します。

  • 左に移動:

    ...
    nint operator <<(nint x, int count);
    nuint operator <<(nuint x, int count);
    
  • 右シフト:

    ...
    nint operator >>(nint x, int count);
    nuint operator >>(nuint x, int count);
    

    >> 演算子は、次に説明するように計算されたビット数だけxを右にシフトします。

    xintnint、または long の型の場合、x の下位ビットは破棄され、残りのビットは右にシフトされ、x が負でない場合は空の上位ビット位置が 0 に設定され、x が負の場合は 1 に設定されます。

    xuintnuint、または ulong の型の場合、x の下位ビットは破棄され、残りのビットは右にシフトされ、上位の空のビット位置は 0 に設定されます。

  • 符号なしの右シフト:

    ...
    nint operator >>>(nint x, int count);
    nuint operator >>>(nuint x, int count);
    

定義済みの演算子の場合、シフトするビット数は次のように計算されます: [...]

  • x の型が nint または nuint の場合、シフト カウントは、32 ビット プラットフォームの下位 5 ビットの count、または 64 ビット プラットフォームの下位 6 ビットの count によって与えられます。

12.12 関係演算子と型検査演算子

12.12.2 整数比較演算子

定義済みの整数比較演算子は次のとおりです。

...
bool operator ==(nint x, nint y);
bool operator ==(nuint x, nuint y);

bool operator !=(nint x, nint y);
bool operator !=(nuint x, nuint y);

bool operator <(nint x, nint y);
bool operator <(nuint x, nuint y);

bool operator >(nint x, nint y);
bool operator >(nuint x, nuint y);

bool operator <=(nint x, nint y);
bool operator <=(nuint x, nuint y);

bool operator >=(nint x, nint y);
bool operator >=(nuint x, nuint y);

12.12 論理演算子

12.12.2 整数論理演算子

定義済みの整数論理演算子は次のとおりです。

...
nint operator &(nint x, nint y);
nuint operator &(nuint x, nuint y);

nint operator |(nint x, nint y);
nuint operator |(nuint x, nuint y);

nint operator ^(nint x, nint y);
nuint operator ^(nuint x, nuint y);

12.22 定数式

定数式には、値型または参照型のいずれかを指定できます。 定数式が値型の場合は、sbytebyteshortushortintuintnintnuintlongulongcharfloatdoubledecimalbool,、任意の列挙型のいずれかである必要があります。

[...]

暗黙的な定数式変換では、定数式の値が変換先の型の範囲内にある場合、型 int の定数式を sbytebyteshortushortuintnintnuint、または ulong に変換できます。

17.4 配列要素アクセス

配列要素には、フォーム A[I₁, I₂, ..., Iₓ]element_access 式を使用してアクセスします。ここで、A は配列型の式であり、各 Iₑintuintnintnuintlongulong であるか、これらの型の 1 つ以上に暗黙的に変換できます。 配列要素アクセスの結果は変数、つまりインデックスによって選択された配列要素です。

23.5 ポインター変換

23.5.1 全般

[...]

さらに、安全でないコンテキストでは、使用可能な明示的な変換のセットが拡張され、次の明示的なポインター変換が含まれます。

  • 任意の pointer_type から他の任意の pointer_typeに変換します。
  • sbytebyteshortushortintuintnintnuintlong、または ulong から任意の pointer_type
  • 任意の pointer_type から sbytebyteshortushortintuintnintnuintlong または ulong

23.6.4 ポインター要素アクセス

[...] フォーム P[E] のポインター要素のアクセスでは、Pvoid* 以外のポインター型の式で、Eintuintnintnuintlong、または ulong に暗黙的に変換できる式でなければなりません。

23.6.7 ポインター算術

安全でないコンテキストでは、+ 演算子と 演算子は、void* を除くすべてのポインター型の値に適用できます。 したがって、T* ポインター型ごとに、次の演算子が暗黙的に定義されています。

[...]
T* operator +(T* x, nint y);
T* operator +(T* x, nuint y);
T* operator +(nint x, T* y);
T* operator +(nuint x, T* y);
T* operator -(T* x, nint y);
T* operator -(T* x, nuint y);

ポインター型 P の式 T* と、型 Nintnuint、または longの式 ulong に基づき、P + NN + P の式は、T*によって指定されたアドレスに N * sizeof(T) を加えた結果として得られる、型 P のポインター値を計算します。 同様に、式 P – N は、P によって指定されたアドレスから N * sizeof(T) を減算した型 T* のポインター値を計算します。

さまざまな考慮事項

重大な変更

この設計の主な影響の 1 つは、System.IntPtrSystem.UIntPtr が一部の組み込み演算子 (変換、単項、二項) を取得することです。
これには checked 演算子が含まれます。つまり、これらの型に対する次の演算子はオーバーフロー時にスローされます。

  • IntPtr + int
  • IntPtr - int
  • IntPtr -> int
  • long -> IntPtr
  • void* -> IntPtr

メタデータ エンコード

この設計は、nintnuintSystem.Runtime.CompilerServices.NativeIntegerAttribute を使用せずに、単に System.IntPtr および System.UIntPtr として出力できることを意味します。
同様に、メタデータの読み込み時に NativeIntegerAttribute を無視できます。