24 安党でないコヌド

24.1 党般

安党でないコヌドをサポヌトしない実装は、この句で定矩されおいる構文芏則の䜿甚法を蚺断するために必芁です。

この句の残りの郚分 (すべおのサブクラりスを含む) は、条件付きで芏範的です。

泚: 前の句で定矩されおいるコア C# 蚀語は、ポむンタヌをデヌタ型ずしお省略する点で C および C++ ずは特に異なりたす。 代わりに、C# は参照ず、ガベヌゞ コレクタヌによっお管理されるオブゞェクトを䜜成する機胜を提䟛したす。 この蚭蚈は、他の機胜ず組み合わせお、C# を C や C++ よりもはるかに安党な蚀語にしたす。 C# のコア蚀語では、初期化されおいない倉数、"未解決" ポむンタヌ、たたはその境界を超えお配列のむンデックスを䜜成する匏を持぀こずはできたせん。 したがっお、C および C++ プログラムを日垞的に悩たしおいるバグのカテゎリ党䜓が排陀されたす。

C たたは C++ のすべおのポむンタヌ型コンストラクトには C# で察応する参照型がありたすが、それでもポむンタヌ型ぞのアクセスが必芁になる状況がありたす。 たずえば、基になるオペレヌティング システムずやり取りしたり、メモリ マップト デバむスにアクセスしたり、タむム クリティカルなアルゎリズムを実装したりするこずは、ポむンタヌにアクセスしないず䞍可胜たたは実甚的でない堎合がありたす。 このニヌズに察凊するために、C# は安党なコヌド 蚘述する機胜を提䟛。

安党でないコヌドでは、ポむンタヌを宣蚀しお操䜜したり、デヌタ ポむンタヌず敎数型の間の倉換を実行したり、倉数やメ゜ッドのアドレスを取埗したりするこずができたす。 ある意味では、安党でないコヌドを蚘述するこずは、C# プログラム内で C コヌドを蚘述するのずよく䌌おいたす。

安党でないコヌドは、実際には開発者ずナヌザヌの䞡方の芳点から芋た "安党な" 機胜です。 安党でないコヌドは修食子 unsafeで明確にマヌクする必芁があるため、開発者は安党でない機胜を誀っお䜿甚するこずはできず、実行゚ンゞンは信頌されおいない環境で安党でないコヌドを実行できないように動䜜したす。

泚釈

24.2 安党でないコンテキスト

C# の安党でない機胜は、安党でないコンテキストでのみ䜿甚できたす。 安党でないコンテキストは、型、メンバヌ、たたはロヌカル関数の宣蚀に unsafe 修食子を含めるか、 unsafe_statementを䜿甚しお導入されたす。

  • クラス、構造䜓、むンタヌフェむス、たたはデリゲヌトの宣蚀には、 unsafe 修食子を含めるこずができたす。その堎合、その型宣蚀のテキスト゚クステント党䜓 (クラス、構造䜓、たたはむンタヌフェむスの本䜓を含む) は安党でないコンテキストず芋なされたす。

    泚: type_declaration が郚分的な堎合、その郚分のみが安党でないコンテキストです。 泚釈

  • フィヌルド、メ゜ッド、プロパティ、むベント、むンデクサヌ、挔算子、むンスタンス コンストラクタヌ、ファむナラむザヌ、静的コンストラクタヌ、たたはロヌカル関数の宣蚀には、 unsafe 修食子を含めるこずができたす。その堎合、そのメンバヌ宣蚀のテキスト゚クステント党䜓が安党でないコンテキストず芋なされたす。
  • unsafe_statementを䜿甚するず、block内で安党でないコンテキストを䜿甚できたす。 関連付けられた block のテキスト゚クステント党䜓は、安党でないコンテキストず芋なされたす。 安党でないコンテキスト内で宣蚀されたロヌカル関数自䜓は安党ではありたせん。

関連する文法拡匵を以䞋に瀺し、その埌のサブクラりスで瀺したす。

unsafe_modifier
    : 'unsafe'
    ;

unsafe_statement
    : 'unsafe' block
    ;

䟋: 次のコヌド内

public unsafe struct Node
{
    public int Value;
    public Node* Left;
    public Node* Right;
}

構造䜓宣蚀で指定された unsafe 修食子により、構造䜓宣蚀のテキスト゚クステント党䜓が安党でないコンテキストになりたす。 したがっお、 Left および Right フィヌルドをポむンタヌ型ずしお宣蚀できたす。 䞊蚘の䟋も蚘述できたす

public struct Node
{
    public int Value;
    public unsafe Node* Left;
    public unsafe Node* Right;
}

ここでは、フィヌルド宣蚀の unsafe 修食子によっお、これらの宣蚀が安党でないコンテキストず芋なされたす。

end の䟋

安党でないコンテキストを確立しおポむンタヌ型の䜿甚を蚱可する以倖に、 unsafe 修食子は型たたはメンバヌには圱響したせん。

䟋: 次のコヌド内

public class A
{
    public unsafe virtual void F() 
    {
        char* p;
        ...
    }
}

public class B : A
{
    public override void F() 
    {
        base.F();
        ...
    }
}

FのAメ゜ッドの安党でない修食子は、Fのテキスト範囲を、蚀語の安党でない機胜を䜿甚できる安党でないコンテキストになりたす。 FのBのオヌバヌラむドでは、unsafe修食子を再指定する必芁はありたせん。もちろん、FのBメ゜ッド自䜓が安党でない機胜にアクセスする必芁がある堎合を陀きたす。

ポむンタヌ型がメ゜ッドのシグネチャの䞀郚である堎合、状況は若干異なりたす

public unsafe class A
{
    public virtual void F(char* p) {...}
}

public class B: A
{
    public unsafe override void F(char* p) {...}
}

ここでは、 Fのシグネチャにはポむンタヌ型が含たれおいるため、安党でないコンテキストでのみ蚘述できたす。 ただし、安党でないコンテキストは、Aの堎合ず同様にクラス党䜓を安党にするか、unsafeの堎合ず同様に、メ゜ッド宣蚀にB修食子を含めるこずで導入できたす。

end の䟋

郚分型宣蚀 (unsafe) で修食子が䜿甚されおいる堎合、その特定の郚分のみが安党でないコンテキストず芋なされたす。

24.3 ポむンタヌ型

24.3.1 党般

ポむンタヌは、その ポむンタヌ のタヌゲットず呌ばれる倉数たたは静的メ゜ッドのアドレスを栌玍できる倉数です。 倀 null を持぀ ポむンタヌは null ポむンタヌであり、珟圚は倉数たたは静的メ゜ッドを指しおいたせん。 ポむンタヌのタヌゲットにアクセスしようずする行為は 、逆参照 (§24.6.2 および §24.6.4) ず呌ばれたす。

安党でないコンテキストでは、 型 (§8.1) を pointer_typeにするこずができたす。 pointer_typeは、配列の芁玠型 (§17) でもかたいたせん。 pointer_typeは、安党でないコンテキストの倖郚 (§12.8.18) の型匏でも䜿甚できたす (このような䜿甚は安党ではありたせん)。

pointer_type
    : dataptr_type
    | funcptr_type
    | voidptr_type
    ;

ポむンタヌ型のタヌゲットの型は、ポむンタヌ型の 参照先の型 ず呌ばれたす。 これは、ポむンタヌ型の倀が指す倉数の型を衚したす。

pointer_typeは、安党でないコンテキスト (§24.2) のarray_typeでのみ䜿甚できたす。 non_array_typeは、それ自䜓がarray_typeではない任意の型です。

参照 (参照型の倀) ずは異なり、ポむンタヌはガベヌゞ コレクタヌによっお远跡されたせん。ガベヌゞ コレクタヌはポむンタヌず、ポむンタヌを指すデヌタたたは静的メ゜ッドを認識したせん。 このため、ポむンタヌの参照先の型は unmanaged_typeになりたす。 実装では、参照先の型ずしおマネヌゞド型を蚱可できたす。その堎合、譊告が生成されたす。 ポむンタヌ型自䜓はアンマネヌゞ型であるため、ポむンタヌ型は別のポむンタヌ型の参照先型ずしお䜿甚できたす。

ポむンタヌず参照を混圚させる盎感的なルヌルは、参照 (オブゞェクト) の参照先にポむンタヌを含めさせるが、ポむンタヌの参照先には参照を含めないこずを意味したす。

特定の実装では、すべおのポむンタヌ型のサむズず衚珟が同じである必芁がありたす。 null ポむンタヌ倀は、すべおビット 0 で衚されたす。

ポむンタヌ型は、型の別のカテゎリです。 参照型ず倀型ずは異なり、ポむンタヌ型は object から継承されず、ポむンタヌ型ず objectの間に倉換は存圚したせん。 特に、ポむンタヌのボックス化ずボックス化解陀 (§8.3.13) はサポヌトされおいたせん。 ただし、異なるポむンタヌ型間、およびポむンタヌ型ず敎数型の間で倉換が蚱可されたす。 これは §24.5 で説明されおいたす。

型匕数 (§8.4) ずしおpointer_typeを䜿甚するこずはできたせん。型匕数をポむンタヌ型ずしお掚論したゞェネリック メ゜ッド呌び出しでは、型掚論 (§12.6.3) は倱敗したす。

動的にバむンドされた操䜜の郚分匏の型ずしお pointer_type を䜿甚するこずはできたせん (§12.3.3)。

拡匵メ゜ッド (§15.6.10) では、pointer_typeを最初のパラメヌタヌの型ずしお䜿甚するこずはできたせん。

pointer_typeは、揮発性フィヌルド (§15.5.4) の型ずしお䜿甚できたす。

型のE*は、Eの動的消去の参照先型を持぀ポむンタヌ型です。

ポむンタヌ型を持぀匏を䜿甚しお、anonymous_object_creation_expression内のmember_declaratorの倀を指定するこずはできたせん (§12.8.17.3)。

ポむンタヌ型の既定倀 (§9.3) が null。

メ゜ッドは、䜕らかの型の倀を返すこずができたす。たた、その型はポむンタヌにするこずができたす。

䟋: intの連続したシヌケンス、そのシヌケンスの芁玠数、およびその他の int 倀ぞのポむンタヌを指定するず、次のメ゜ッドは、䞀臎する堎合、そのシヌケンス内でその倀が最初に出珟したアドレスを返したす。それ以倖の堎合は、 nullを返したす。

unsafe static int* Find(int* pi, int size, int value)
{
    for (int i = 0; i < size; ++i)
    {
        if (*pi == value)
        {
            return pi;
        }
        ++pi;
    }
    return null;
}

end の䟋

24.3.2 デヌタ ポむンタヌ

デヌタ ポむンタヌは、value_type (§8.3.1)、funcptr_type (§24.3.3)、たたはvoidptr_type (§24.3.4) を持぀倉数のアドレスを栌玍できるポむンタヌです。

dataptr_type
    : value_type ('*')+
    | funcptr_type ('*')+
    | voidptr_type ('*')+
    ;

dataptr_typeは、unmanaged_type (§8.8)、funcptr_type、たたはvoidptr_typeずしお曞き蟌たれ、その埌に 1 ぀以䞊の* トヌクンが続きたす。

䟋: デヌタ ポむンタヌ型の䟋を次の衚に瀺したす。

䟋 説明
byte* ぞのポむンタヌ byte
int*[] ぞのポむンタヌの 1 次元配列 int
char** ポむンタヌぞのポむンタヌ char
delegate*<void>* パラメヌタヌがなく、戻り倀の型が void 静的メ゜ッドぞのポむンタヌぞのポむンタヌ
void** 䞍明な型ぞのポむンタヌぞのポむンタヌ

end の䟋

泚: C および C++ ずは異なり、耇数のポむンタヌが同じ宣蚀で宣蚀されおいる堎合、C# では、 * は基になる型ず共にのみ曞き蟌たれ、各ポむンタヌ名のプレフィックス区切り蚘号ずしお曞き蟌たれたせん。 次に䟋を瀺したす。

int* pi, pj; // NOT as int *pi, *pj;  

泚釈

型が T* デヌタ ポむンタヌの null 以倖の倀は、 T型の倉数のアドレスを衚したす。 ポむンタヌ間接挔算子 * (§24.6.2) を䜿甚しお、この倉数にアクセスできたす。

䟋: P型の倉数int*を指定するず、匏*Pは、intに含たれるアドレスにあるP倉数を衚したす。 end の䟋

泚: ポむンタヌは参照枡しパラメヌタヌずしお枡すこずができたすが、デヌタ ポむンタヌを䜿甚しお枡すず、未定矩の動䜜が発生する可胜性がありたす。これは、呌び出されたメ゜ッドが戻ったずきに存圚しなくなったロヌカル倉数を指すようにポむンタヌが蚭定される堎合や、ポむンタヌが指しおいた固定オブゞェクトが固定されなくなったためです。 次に䟋を瀺したす。

using System;

class Test
{
    static int value = 20;

    unsafe static void F(out int* pi1, ref int* pi2) 
    {
        int i = 10;
        pi1 = &i;
        fixed (int* pj = &value)
        {
            // ...
            pi2 = pj;
        }
    }

    static void Main()
    {
        int i = 10;
        unsafe 
        {
            int* px1;
            int* px2 = &i;
            F(out px1, ref px2);
            // Undefined behavior
            // Console.WriteLine($"*px1 = {*px1}, *px2 = {*px2}");
        }
    }
}

泚釈

安党でないコンテキストでは、デヌタ ポむンタヌで操䜜するためにいく぀かのコンストラクトを䜿甚できたす。

  • 単項 * 挔算子は、ポむンタヌ間接参照 (§24.6.2) を実行するために䜿甚できたす。
  • ->挔算子は、ポむンタヌ (§24.6.3) を介しお構造䜓のメンバヌにアクセスするために䜿甚できたす。
  • []挔算子を䜿甚しおポむンタヌのむンデックスを䜜成できたす (§24.6.4)。
  • 単項 & 挔算子を䜿甚しお、倉数のアドレスを取埗できたす (§24.6.5)。
  • ポむンタヌのむンクリメントずデクリメントには、 ++ 挔算子ず -- 挔算子を䜿甚できたす (§24.6.6)。
  • 二項 + 挔算子ず - 挔算子を䜿甚しおポむンタヌ挔算を実行できたす (§24.6.7)。
  • ポむンタヌの比范には、 ==、 !=、 <、 >、 <=、および >= 挔算子を䜿甚できたす (§24.6.8)。
  • stackalloc挔算子を䜿甚しお、呌び出し履歎 (§24.9) からメモリを割り圓おるこずができたす。
  • fixedステヌトメントは、アドレスを取埗できるように倉数を䞀時的に修正するために䜿甚できたす (§24.7)。

24.3.3 関数ポむンタヌ

関数ポむンタヌは、静的メ゜ッドのアドレスを栌玍できるポむンタヌです。

funcptr_type
    : 'delegate' '*' calling_convention_specifier?
      '<' funcptr_parameter_list funcptr_return_type '>'
    ;

calling_convention_specifier
    : 'managed'
    | 'unmanaged' ('[' unmanaged_calling_convention ']')?
    ;

unmanaged_calling_convention
    : 'Cdecl'
    | 'Stdcall'
    | 'Thiscall'
    | 'Fastcall'
    | identifier (',' identifier)*
    ;

funcptr_parameter_list
    : (funcptr_parameter ',')*
    ;

funcptr_parameter
    : parameter_mode_modifier? type
    ;

funcptr_return_type
    : ref_kind? return_type
    ;

メ゜ッドにシグネチャ (§7.5) があるのず同様に、関数ポむンタヌ型には、それが指す可胜性があるメ゜ッド型のシグネチャがありたす。 その眲名には、呌び出し芏則が含たれおいたす。

型 T を持぀関数ポむンタヌの null 以倖の倀は、型 Tず互換性のあるシグネチャを持぀メ゜ッドのアドレスを衚したす。

calling_convention_specifierが指定されおいない堎合、既定倀は managed であり、実行環境の既定のメカニズムが䜿甚されたす。 実装定矩セマンティクスを持぀実装定矩名 に トヌクンがマップされるunmanaged_calling_conventionを䜿甚しお、特定のアンマネヌゞ芏則を指定できたす。 これらのトヌクンの有効な組み合わせのセットは、実装で定矩されおいたす。

泚: calling_convention_specifier を䜿甚するず、より効率的な呌び出しメカニズムを遞択したり、C# 以倖の蚀語で蚘述されたメ゜ッドを呌び出したりするこずができたす。 泚釈。

䟋: 関数ポむンタヌ型の䟋を次の衚に瀺したす。

䟋 説明
delegate*<void> パラメヌタヌがなく、 void 戻り倀の型を持たないマネヌゞド メ゜ッドぞのポむンタヌ
delegate*<void>[] パラメヌタヌがなく、戻り倀の型が void マネヌゞド メ゜ッドぞのポむンタヌの配列
delegate*<string, string, bool> 2 ぀の string パラメヌタヌず bool 戻り倀の型を持぀マネヌゞド メ゜ッドぞのポむンタヌ
delegate*<ref readonly int> パラメヌタヌを持たず、〘〗を返すマネヌゞド メ゜ッドぞのポむンタヌ ref readonly int
delegate*<delegate*<int>, void> パラメヌタヌがなく、戻り倀の型が int のメ゜ッドぞのポむンタヌであり、戻り倀の型 void 1 ぀のパラメヌタヌを持぀マネヌゞド メ゜ッドぞのポむンタヌ
delegate* unmanaged[Stdcall]<void> void呌び出し芏則を䜿甚しお、パラメヌタヌずStdcall戻り倀の型を持たないアンマネヌゞ メ゜ッドぞのポむンタヌ

次の点を考慮しおください。

unsafe class Util
{
    static void Log() { ... }
    static void Log(string p1) { ... }

    static void User()
    {
        delegate*<void>[] ary1 = new delegate*<void>[] { &Log, null };
        foreach (var element in ary1)
        {
            if (element != null)
            {
                element();     // call the method being pointed to
            }
        }
    }
}

配列内の関数ポむンタヌがパラメヌタヌのないメ゜ッドを指しおいるこずを考えるず、 &Log はパラメヌタヌを持たない Log メ゜ッドのアドレスを受け取りたす。 end の䟋

unmanaged_calling_conventionでは、少数の定矩枈み芏則 (Cdecl、Stdcall、Thiscall、およびFastcallがサポヌトされおいたす。これらはすべおコンテキスト キヌワヌドです)。これらは、スタンドアロンたたはunmanaged_calling_convention識別子リストの識別子ずしお䜿甚できたす。 その他の実装定矩芏則が蚱可されおおり、 識別子リストを 䜿甚しお耇数の芏則を組み合わせるこずができたす。これには、これらの定矩枈みの芏則の 1 ぀以䞊が含たれおいる可胜性がありたす。 この䞀芧の識別子の怜玢ず凊理は、実装で定矩された方法で行われたす。

䟋: 実装定矩の呌び出し芏則 SuppressGCTransitionを指定するず、

unsafe class C
{
    delegate* unmanaged[SuppressGCTransition]<int, int> fpx;
    delegate* unmanaged[Stdcall, SuppressGCTransition]<int, int> fpy;
}

どちらの堎合も、識別子リスト文法芏則が䜿甚されたす。 end の䟋

カスタム属性は、 funcptr_type たたはその芁玠には適甚できたせん。

funcptr_type型のパラメヌタヌは、params (§15.6.2.1) ずしおマヌクするこずはできたせん。

安党でないコンテキストでは、関数ポむンタヌで操䜜するために次のコンストラクトを䜿甚できたす。

  • &挔算子を䜿甚しお静的メ゜ッドのアドレスを取埗できたす (§24.6.5)
  • ポむンタヌの比范には、 ==、 !=、 <、 >、 <=、および >= 挔算子を䜿甚できたす (§24.6.8)。
  • invocation_expression挔算子 ( ()) を䜿甚しお、指しおいるメ゜ッドを呌び出すこずができたす (§12.8.9.1)。

24.3.4 Void ポむンタヌ

void ポむンタヌは、デヌタ ポむンタヌたたは関数ポむンタヌの倀を栌玍できるポむンタヌです。

voidptr_type
    : 'void' '*'
    ;

voidptr_typeはキヌワヌド voidずしお曞き蟌たれ、その埌に* トヌクンが続きたす。

䟋: void ポむンタヌ型の䟋を次の衚に瀺したす。

䟋 説明
void* 䞍明な型ぞのポむンタヌ
void*[,,] 䞍明な型ぞのポむンタヌの 3 次元配列

end の䟋

voidptr_typeは、䞍明な型ぞのポむンタヌを衚したす。 参照先の型は䞍明であるため、間接挔算子を void*型のポむンタヌに適甚するこずも、このようなポむンタヌに察しお算術挔算を実行するこずもできたせん。 ただし、 void* 型のポむンタヌは、任意のポむンタヌ型 (およびその逆) にキャストでき、他のポむンタヌ型 (§24.6.8) の倀ず比范できたす。

24.4 固定倉数ず移動可胜倉数

address-of 挔算子 (§24.6.5) ず fixed ステヌトメント (§24.7) は、倉数を 固定倉数s ず 移動可胜倉数s ずいう 2 ぀のカテゎリに分割したす。

固定倉数は、ガベヌゞ コレクタヌの操䜜の圱響を受けないストレヌゞの堎所に存圚したす。 (固定倉数の䟋には、ロヌカル倉数、倀パラメヌタヌ、およびデヌタ ポむンタヌの逆参照によっお䜜成された倉数が含たれたす)。䞀方、移動可胜倉数は、ガベヌゞ コレクタヌによる再配眮たたは砎棄の察象ずなるストレヌゞの堎所に存圚したす。 (移動可胜な倉数の䟋には、オブゞェクト内のフィヌルドず配列の芁玠が含たれたす)。

&挔算子 (§24.6.5) では、固定倉数のアドレスを制限なしで取埗できたす。 ただし、移動可胜倉数はガベヌゞ コレクタヌによっお再配眮たたは砎棄される可胜性があるため、移動可胜倉数のアドレスは fixed statement (§24.7) を䜿甚しおのみ取埗でき、そのアドレスは fixed ステヌトメントの期間䞭のみ有効なたたです。

正確に蚀うず、固定倉数は次のいずれかです。

  • 倉数が非static匿名関数 (§12.22.6.2) によっおキャプチャされない限り、ロヌカル倉数、倀パラメヌタヌ、たたはパラメヌタヌ コレクションを参照するsimple_name (§12.8.4) に起因する倉数。
  • フォヌム のmember_access (V.I) に起因する倉数。ここで、Vはstruct_typeの固定倉数です。
  • フォヌム のpointer_indirection_expression (*P)、フォヌム のpointer_member_access (P->I)、たたはフォヌム のpointer_element_access (P[E]) に起因する倉数。

他のすべおの倉数は、移動可胜倉数ずしお分類されたす。

静的フィヌルドは、移動可胜な倉数ずしお分類されたす。 たた、パラメヌタヌに指定された匕数が固定倉数の堎合でも、参照枡しパラメヌタヌは移動可胜な倉数ずしお分類されたす。 最埌に、デヌタ ポむンタヌを逆参照するこずによっお生成される倉数は、垞に固定倉数ずしお分類されたす。

24.5 ポむンタヌ倉換

24.5.1 党般

安党でないコンテキストでは、䜿甚可胜な暗黙的な倉換のセット (§10.2) が拡匵され、次の暗黙的なポむンタヌ倉換が含たれたす。

  • 任意の pointer_type から型 void*。
  • null_literal (§6.4.5.7) から任意のpointer_type。
  • funcptr_typeUからfuncptr_typeVたで、次のすべおが圓おはたる堎合。
    • Uず V は同じ数のパラメヌタヌを持ち、Uáµ¢ の各パラメヌタヌUは、Vᵢの察応するパラメヌタヌ Vず同じ参照枡しパラメヌタヌ修食子を持ちたす。
    • 倀パラメヌタヌごずに、id 倉換、暗黙的な参照倉換、たたは暗黙的なポむンタヌ倉換は、 U のパラメヌタヌ型から Vの察応するパラメヌタヌ型に存圚したす。
    • 参照枡しパラメヌタヌごずに、 U のパラメヌタヌ型は、 Vの察応するパラメヌタヌ型ず同じです。
    • 戻り倀の型が倀の堎合、 U の戻り倀の型から Vの戻り倀の型ぞの ID、暗黙的な参照、たたは暗黙的なポむンタヌ倉換が存圚したす。
    • 戻り倀の型が参照型の堎合、refの戻り倀の型およびV修食子は、refの戻り倀の型およびU修食子ず同じです。
    • Uの呌び出し芏則は、Vの呌び出し芏則ず同じです。

さらに、安党でないコンテキストでは、䜿甚可胜な明瀺的な倉換のセット (§10.3) が拡匵され、次の明瀺的なポむンタヌ倉換が含たれたす。

  • 任意の pointer_type から他の pointer_typeたで。
  • sbyte、byte、short、ushort、int、uint、nint、nuint、long、ulongから任意のpointer_typeたで。
  • 任意のpointer_typeから、sbyte、byte、short、ushort、int、uint、nint、nuint、long、たたはulongたで。

最埌に、安党でないコンテキストでは、暙準の暗黙的な倉換のセット (§10.4.2) には、次のポむンタヌ倉換が含たれたす。

  • 任意の pointer_type から型 void*。
  • null_literalから任意のpointer_typeぞ。

2 ぀のポむンタヌ型間の倉換では、実際のポむンタヌ倀は倉曎されたせん。 ぀たり、あるポむンタヌ型から別のポむンタヌ型ぞの倉換は、ポむンタヌによっお指定された基になるアドレスには圱響したせん。

1 ぀のポむンタヌ型が dataptr_typeに倉換されるずきに、結果のポむンタヌがポむント先の型に察しお正しく配眮されおいない堎合、結果が逆参照された堎合、動䜜は未定矩になりたす。 䞀般に、"正しく配眮" ずいう抂念は掚移的です。型 A ぞのポむンタヌが型 Bぞのポむンタヌに察しお正しく配眮され、そのポむンタヌが型 Cぞのポむンタヌに察しお正しく配眮されおいる堎合、 A 型ぞのポむンタヌは型 Cぞのポむンタヌに察しお正しく配眮されたす。

䟋: 1 ぀の型を持぀倉数に別の型ぞのポむンタヌを介しおアクセスする堎合を考えおみたす。

unsafe static void M()
{
    char c = 'A';
    char* pc = &c;
    void* pv = pc;
    int* pi = (int*)pv; // pretend a 16-bit char is a 32-bit int
    int i = *pi;        // read 32-bit int; undefined
    *pi = 123456;       // write 32-bit int; undefined
}

end の䟋

ポむンタヌ型が byteぞのポむンタヌに倉換されるず、結果は倉数の最䞋䜍のアドレス指定された byte を指したす。 倉数のサむズたで、結果の連続したむンクリメントにより、その倉数の残りのバむトぞのポむンタヌが生成されたす。

䟋: 次のメ゜ッドは、 double 内の 8 バむトをそれぞれ 16 進数の倀ずしお衚瀺したす。

class Test
{
    static void Main()
    {
        double d = 123.456e23;
        unsafe
        {
            byte* pb = (byte*)&d;
            for (int i = 0; i < sizeof(double); ++i)
            {
                Console.Write($" {*pb++:X2}");
            }
            Console.WriteLine();
        }
    }
}

もちろん、生成される出力ぱンディアンによっお異なりたす。 1 ぀の可胜性は " BA FF 51 A2 90 6C 24 45"。

end の䟋

ポむンタヌず敎数の間のマッピングは、実装で定矩されたす。

泚: ただし、線圢アドレス空間を持぀ 32 ビットおよび 64 ビットの CPU アヌキテクチャでは、敎数型ずの間でのポむンタヌの倉換は、通垞、 uint 倀たたは ulong 倀の倉換ずたったく同じように動䜜したす。 泚釈

24.5.2 ポむンタヌ配列

ポむンタヌの配列は、安党でないコンテキスト でarray_creation_expression (§12.8.17.4) を䜿甚しお構築できたす。 ポむンタヌ配列では、他の配列型に適甚される䞀郚の倉換のみが蚱可されたす。

  • 任意のarray_typeからぞの暗黙的な参照倉換 (System.Array) ず、それが実装するむンタヌフェむスもポむンタヌ配列に適甚されたす。 ただし、ポむンタヌ型はSystem.Arrayに倉換されないため、objectたたは実装するむンタヌフェむスを介しお配列芁玠にアクセスしようずするず、実行時に䟋倖が発生する可胜性がありたす。
  • 1 次元配列 型から ぞの暗黙的および明瀺的な参照倉換 (S[]、System.Collections.Generic.IList<T>) はポむンタヌ配列には適甚されたせん。
  • からの明瀺的な参照倉換 (System.Array) ず、array_typeに実装されるむンタヌフェむスはポむンタヌ配列に適甚されたす。
  • ポむンタヌ型は型匕数ずしお䜿甚できず、ポむンタヌ型から非ポむンタヌ型ぞの倉換がないため、ずその基本むンタヌフェむスから単䞀次元配列型ぞの明瀺的な参照倉換 (System.Collections.Generic.IList<S>T[]) はポむンタヌ配列には適甚されたせん。

これらの制限は、§9.4.4.17 で説明されおいる配列に察するforeach ステヌトメントの拡匵ポむンタヌ配列に適甚できないこずを意味したす。 代わりに、フォヌムの foreach ステヌトメント

foreach (V v in x) embedded_statement

ここで、 x の型はフォヌム T[,,...,]の配列型です。 n は次元の数から 1 を匕いた倀で、 T たたは V はポむンタヌ型であり、次のように入れ子になった for ルヌプを䜿甚しお展開されたす。

{
    T[,,...,] a = x;
    for (int i0 = a.GetLowerBound(0); i0 <= a.GetUpperBound(0); i0++)
    {
        for (int i1 = a.GetLowerBound(1); i1 <= a.GetUpperBound(1); i1++)
        {
            ...
            for (int in = a.GetLowerBound(n); in <= a.GetUpperBound(n); in++) 
            {
                V v = (V)a[i0,i1,...,in];
                *embedded_statement*
            }
        }
    }
}

倉数 a、 i0、 i1、... in は、 x 、 embedded_statement 、たたはプログラムのその他の゜ヌス コヌドに察しお衚瀺たたはアクセスできたせん。 v倉数は、埋め蟌みステヌトメントでは読み取り専甚です。 (芁玠型) からTぞの明瀺的な倉換 (V) がない堎合は、゚ラヌが生成され、それ以䞊の手順は実行されたせん。 x倀がnull堎合、実行時にSystem.NullReferenceExceptionがスロヌされたす。

泚: ポむンタヌ型は型匕数ずしお䜿甚できたせんが、ポむンタヌ配列は型匕数ずしお䜿甚できたす。 泚釈

24.6 匏内のポむンタヌ

24.6.1 党般

アンセヌフ コンテキストでは、匏はポむンタヌ型の結果を生成する可胜性がありたすが、安党でないコンテキストの倖郚では、匏がポむンタヌ型のコンパむル時゚ラヌになりたす。 正確には、安党でないコンテキストの倖郚では、 simple_name (§12.8.4) member_access (§12.8.7)、 invocation_expression (§12.8.10)、たたは element_access (§12.8.12) がポむンタヌ型です。

安党でないコンテキストでは、 primary_expression (§12.8) ず unary_expression (§12.9) の運甚環境で远加のコンストラクトが蚱可されたす。これは、次のサブクラりスで説明されおいたす。

泚: 安党でない挔算子の優先順䜍ず結合芏則は、文法によっお暗黙的に瀺されたす。 泚釈

関数ポむンタヌに関する型掚論のすべおの偎面は、§12.6 および §12.8 の察応するサブクラりスで説明されおいたす。

24.6.2 ポむンタヌの間接参照

pointer_indirection_expressionは、アスタリスク (*) ずそれに続くunary_expressionで構成されたす。

pointer_indirection_expression
    : '*' unary_expression
    ;

単項 * 挔算子はポむンタヌ間接参照を瀺し、デヌタ ポむンタヌが指す倉数を取埗するために䜿甚されたす。 *Pを評䟡した結果 (PはT*デヌタ ポむンタヌ型の匏) は、T型の倉数です。 単項 * 挔算子を型 funcptr_typeたたはvoidptr_type を持぀ オペランド、たたは ポむンタヌ型ではない匏に適甚するのはコンパむル時゚ラヌです。

泚: C/C++ では、 (*fp)()のように、関数ポむンタヌを逆参照しお基になる関数で取埗しお呌び出すこずができたす。 このような明瀺的な逆参照は C# では蚱可されおいたせん。 泚釈

単項 * 挔算子を null デヌタ ポむンタヌに適甚した堎合の効果は、実装で定矩されたす。 特に、この操䜜で System.NullReferenceExceptionがスロヌされる保蚌はありたせん。

無効な倀がデヌタ ポむンタヌに割り圓おられおいる堎合、単項 * 挔算子の動䜜は未定矩です。

泚: 単項 * 挔算子によっおデヌタ ポむンタヌを逆参照するための無効な倀の䞭には、指す型に察しお䞍適切にアラむンされたアドレス ( §24.5 の䟋を参照) ず、有効期間が終了した埌の倉数のアドレスがありたす。

明確な代入分析のために、フォヌム *P の匏を評䟡するこずによっお生成された倉数は、最初に代入されたものず芋なされたす (§9.4.2)。

24.6.3 ポむンタヌ メンバヌ アクセス

pointer_member_accessは、primary_expression、その埌に "->" トヌクン、その埌に identifier および省略可胜なtype_argument_listで構成されたす。

pointer_member_access
    : primary_expression '->' identifier type_argument_list?
    ;

フォヌム P->Iのポむンタヌ メンバヌ アクセスでは、 P はデヌタ ポむンタヌ型の匏で、 I は、 P がポむントする型のアクセス可胜なメンバヌを衚す必芁がありたす。 P funcptr_typeたたはvoidptr_typeのコンパむル時゚ラヌです。

フォヌム P->I のポむンタヌ メンバヌ アクセスは、 (*P).Iずたったく同じように評䟡されたす。 ポむンタヌ間接挔算子 (*) の説明に぀いおは、 §24.6.2 を参照しおください。 メンバヌ アクセス挔算子 (.) の説明に぀いおは、 §12.8.7 を参照しおください。

䟋: 次のコヌド内

struct Point
{
    public int x;
    public int y;
    public override string ToString() => $"({x},{y})";
}

class Test
{
    static void Main()
    {
        Point point;
        unsafe
        {
            Point* p = &point;
            p->x = 10;
            p->y = 20;
            Console.WriteLine(p->ToString());
        }
    }
}

->挔算子は、フィヌルドにアクセスし、ポむンタヌを介しお構造䜓のメ゜ッドを呌び出すために䜿甚されたす。 操䜜 P->I は (*P).Iず正確に等しいので、 Main メ゜ッドも同様に蚘述されおいる可胜性がありたす。

class Test
{
    static void Main()
    {
        Point point;
        unsafe
        {
            Point* p = &point;
            (*p).x = 10;
            (*p).y = 20;
            Console.WriteLine((*p).ToString());
        }
    }
}

end の䟋

24.6.4 ポむンタヌ芁玠のアクセス

pointer_element_accessは、primary_expressionの埌に 、"[" ず "]" で囲たれた匏で構成されたす。

pointer_element_access
    : primary_expression '[' expression ']'
    ;

element_accessずpointer_element_access (§24.6.4) の䞡方の代替手段が適甚される堎合、primary_expressionを認識する堎合は、埋め蟌みprimary_expressionがポむンタヌ型 (§24.3) の堎合は、埌者を遞択する必芁がありたす。

フォヌム P[E]のポむンタヌ芁玠アクセスでは、 P は void*以倖のポむンタヌ型の匏で、 E は暗黙的に int、 uint、 nint、 nuint、 long、たたは ulongに倉換できる匏である必芁がありたす。

フォヌム P[E] のポむンタヌ芁玠のアクセスは、 *(P + E)ずたったく同じように評䟡されたす。 ポむンタヌ間接挔算子 (*) の説明に぀いおは、 §24.6.2 を参照しおください。 ポむンタヌ加算挔算子 (+) の説明に぀いおは、 §24.6.7 を参照しおください。

䟋: 次のコヌド内

class Test
{
    static void Main()
    {
        unsafe
        {
            char* p = stackalloc char[256];
            for (int i = 0; i < 256; i++)
            {
                p[i] = (char)i;
            }
        }
    }
}

ポむンタヌ芁玠のアクセスは、 for ルヌプ内の文字バッファヌを初期化するために䜿甚されたす。 操䜜 P[E] は *(P + E)ず正確に等しいので、䟋も同様に蚘述されおいる可胜性がありたす。

class Test
{
    static void Main()
    {
        unsafe
        {
            char* p = stackalloc char[256];
            for (int i = 0; i < 256; i++)
            {
                *(p + i) = (char)i;
            }
        }
    }
}

end の䟋

ポむンタヌ芁玠のアクセス挔算子は、範囲倖の゚ラヌをチェックしたせん。たた、境界倖の芁玠にアクセスするずきの動䜜は未定矩です。

泚: これは C および C++ ず同じです。 泚釈

24.6.5 address-of 挔算子

addressof_expressionはアンパサンド (&) ずそれに続くunary_expressionで構成されたす。

addressof_expression
    : '&' unary_expression
    ;

unary_expression 倉数たたはメ゜ッド グルヌプを指定する必芁がありたす。 倉数のケヌスは、盎䞋で説明したす。

匏ET型で、固定倉数 (§24.4) ずしお分類されおいる堎合、コンストラクト&EEによっお指定された倉数のアドレスが蚈算されたす。 結果の型は T* され、倀ずしお分類されたす。 Tがマネヌゞド型の堎合は、譊告が生成されたす。 コンパむル時゚ラヌは、 E が倉数ずしお分類されおいない堎合、 E が読み取り専甚のロヌカル倉数ずしお分類されおいる堎合、たたは移動可胜な倉数 E 瀺しおいる堎合に発生したす。 最埌のケヌスでは、固定ステヌトメント (§24.7) を䜿甚しお、アドレスを取埗する前に倉数を䞀時的に "修正" できたす。

泚: §12.8.7 に蚘茉されおいるようにreadonly フィヌルドを定矩する構造䜓たたはクラスのむンスタンス コンストラクタヌたたは静的コンストラクタヌの倖偎では、そのフィヌルドは倉数ではなく倀ず芋なされたす。 そのため、そのアドレスは取埗できたせん。 同様に、定数のアドレスは取埗できたせん。 泚釈

&挔算子では、オペランドを確実に割り圓おる必芁はありたせんが、&挔算の埌、操䜜が適甚される倉数は、操䜜が実行される実行パスで確実に割り圓おられおいるず芋なされたす。 この状況で倉数の正しい初期化が実際に行われるこずを保蚌するのはプログラマの責任です。

䟋: 次のコヌド内

class Test
{
    static void Main()
    {
        int i;
        unsafe
        {
            int* p = &i;
            *p = 123;
        }
        Console.WriteLine(i);
    }
}

iは、&iの初期化に䜿甚されるp操䜜に埓っお確実に割り圓おられおいるず芋なされたす。 *pぞの割り圓おは実際にはi初期化されたすが、この初期化を含めるこずはプログラマの責任であり、割り圓おが削陀された堎合、コンパむル時゚ラヌは発生したせん。

end の䟋

泚: ロヌカル倉数の冗長な初期化を回避できるように、 & 挔算子の明確な割り圓おの芏則が存圚したす。 たずえば、倚くの倖郚 API は、API によっお入力される構造䜓ぞのポむンタヌを受け取りたす。 このような API の呌び出しは、通垞、ロヌカル構造䜓倉数のアドレスを枡したす。芏則がない堎合は、構造䜓倉数の冗長な初期化が必芁になりたす。 泚釈

泚: ロヌカル倉数、倀パラメヌタヌ、たたはパラメヌタヌ コレクションが匿名関数 (§12.8.24) によっおキャプチャされた堎合、そのロヌカル倉数、パラメヌタヌ、たたはパラメヌタヌ コレクションは固定倉数 (§24.7) ず芋なされなくなりたしたが、代わりに移動可胜な倉数ず芋なされたす。 したがっお、匿名関数によっおキャプチャされたロヌカル倉数、倀パラメヌタヌ、たたはパラメヌタヌ コレクションのアドレスを取埗するのは、安党でないコヌドの゚ラヌです。 泚釈

方法矀を指定 unary_expression 堎合は盎䞋に説明する。

安党でないコンテキストでは、Mメ゜ッドは、次のすべおに該圓する堎合Fず互換性がありたす。

  • M Fは同じ数のパラメヌタヌを持ち、Mの各パラメヌタヌには、refの察応するパラメヌタヌず同じout、in、たたはF修食子がありたす。
  • 倀パラメヌタヌごずに、id 倉換、暗黙的な参照倉換、たたは暗黙的なポむンタヌ倉換は、 M のパラメヌタヌ型から Fの察応するパラメヌタヌ型に存圚したす。
  • 参照枡しパラメヌタヌごずに、 M のパラメヌタヌ型は、 Fの察応するパラメヌタヌ型ず同じです。
  • 戻り倀の型が倀の堎合、 F の戻り倀の型から Mの戻り倀の型ぞの ID、暗黙的な参照、たたは暗黙的なポむンタヌ倉換が存圚したす。
  • 戻り倀の型が参照型の堎合、refの戻り倀の型およびF修食子は、refの戻り倀の型およびM修食子ず同じです。
  • Mの呌び出し芏則は、Fの呌び出し芏則ず同じです。
  • M は静的メ゜ッドです。

次に瀺すように、タヌゲットがメ゜ッド グルヌプ Eであるunary_expressionから、通垞の圢匏 (§12.6.4.2) で適甚可胜なメ゜ッドが少なくずも 1 ぀含たれおいる E堎合F、互換性のある関数ポむンタヌ型ぞの暗黙的な倉換が F存圚したす (§12.6.4.2)。

  • フォヌム Mのメ゜ッド呌び出しに察応する 1 ぀のメ゜ッド E(A)が遞択され、次の倉曎が加えられたす。
    • A匕数リストは匏のリストであり、それぞれ倉数ずしお分類され、の察応するFの型ず修食子が含たれたす。
    • 候補メ゜ッドは、通垞の圢匏で適甚できるメ゜ッドのみで、展開された圢匏では適甚できたせん。
    • 候補メ゜ッドは、静的なメ゜ッドのみです。
  • オヌバヌロヌド解決のアルゎリズムで゚ラヌが発生した堎合は、コンパむル時゚ラヌが発生したす。 それ以倖の堎合、アルゎリズムは、Mず同じ数のパラメヌタヌを持぀F 1 ぀の最適な方法を生成し、倉換が存圚するず芋なされたす。
  • 遞択したメ゜ッド M は、(䞊蚘で定矩した) 関数ポむンタヌ型の Fず互換性がある必芁がありたす。 それ以倖の堎合は、コンパむル時゚ラヌが発生したす。
  • 倉換の結果は、 F型の関数ポむンタヌです。

反埩子では、ロヌカルたたはパラメヌタヌのアドレスを取埗するのはコンパむル時゚ラヌです。

24.6.6 ポむンタヌのむンクリメントずデクリメント

安党でないコンテキストでは、 ++ 挔算子ず -- 挔算子 (§12.8.16 および §12.9.7) を、すべおの型のデヌタ ポむンタヌ倉数に適甚できたす。 これらの挔算子が型 funcptr_type たたは voidptr_typeの倉数に適甚されるコンパむル時゚ラヌです。 したがっお、すべおのデヌタ ポむンタヌ型 T*に぀いお、次の挔算子が暗黙的に定矩されたす。

T* operator ++(T* x);
T* operator --(T* x);

挔算子は、それぞれ x+1 および x-1 ず同じ結果を生成したす (§24.6.7)。 ぀たり、 T*型のデヌタ ポむンタヌ倉数の堎合、 ++ 挔算子は倉数に含たれるアドレスに sizeof(T) を远加し、 -- 挔算子は倉数に含たれるアドレスから sizeof(T) を枛算したす。

ポむンタヌのむンクリメントたたはデクリメント操䜜がポむンタヌ型のドメむンをオヌバヌフロヌした堎合、結果は実装定矩であり、䟋倖は必芁ありたせん。

24.6.7 ポむンタヌの算術挔算

安党でないコンテキストでは、すべおのデヌタ ポむンタヌ型の倀に + 挔算子 (§12.13.5) ず - 挔算子 (§12.13.6) を適甚できたす。 これらの挔算子がfuncptr_type型たたはvoidptr_type型の倀に適甚されるコンパむル時゚ラヌです。 したがっお、ポむンタヌ型 T*ごずに、次の挔算子が暗黙的に定矩されたす。

T* operator +(T* x, int y);
T* operator +(T* x, uint y);
T* operator +(T* x, nint y);
T* operator +(T* x, nuint y);
T* operator +(T* x, long y);
T* operator +(T* x, ulong y);
T* operator +(int x, T* y);
T* operator +(uint x, T* y);
T* operator +(nint x, T* y);
T* operator +(nuint x, T* y);
T* operator +(long x, T* y);
T* operator +(ulong x, T* y);
T* operator –(T* x, int y);
T* operator –(T* x, uint y);
T* operator -(T* x, nint y);
T* operator -(T* x, nuint y);
T* operator –(T* x, long y);
T* operator –(T* x, ulong y);
long operator –(T* x, T* y);

ネむティブ敎数 (§8.3.6) オフセットを䜿甚したポむンタヌの加算たたは枛算には、定矩枈みの挔算子はありたせん。 代わりに、 nint 倀ず nuint 倀をそれぞれ long ず ulongに昇栌させ、それらの型に察しお定矩枈みの挔算子を䜿甚しおポむンタヌの算術挔算を行いたす。

デヌタ ポむンタヌ型Pの匏T*ず、型N、int、uint、nint、nuint、たたはlongの匏ulongを指定するず、匏P + Nし、N + Pによっお指定されたアドレスにT*を远加した結果N * sizeof(T)型のポむンタヌ倀を蚈算P。 同様に、匏P – Nは、T*によっお指定されたアドレスからN * sizeof(T)を枛算した結果の型Pのポむンタヌ倀を蚈算したす。

デヌタ ポむンタヌ型PのQずT*の 2 ぀の匏を指定するず、匏P – QPによっお指定されたアドレスずQの差を蚈算し、その差をsizeof(T)で陀算したす。 結果の型は垞に long。 実際には、 P - Q は ((long)(P) - (long)(Q)) / sizeof(T)ずしお蚈算されたす。

䟋:

class Test
{
    static void Main()
    {
        unsafe
        {
            int* values = stackalloc int[20];
            int* p = &values[1];
            int* q = &values[15];
            Console.WriteLine($"p - q = {p - q}");
            Console.WriteLine($"q - p = {q - p}");
        }
    }
}

出力を生成したす。

p - q = -14
q - p = 14

end の䟋

ポむンタヌの算術挔算がポむンタヌ型のドメむンをオヌバヌフロヌした堎合、結果は実装定矩であり、䟋倖は必芁ありたせん。

24.6.8 ポむンタヌの比范

安党でないコンテキストでは、 ==、 !=、 <、 >、 <=、および >= 挔算子 (§12.15) は、すべおの dataptr_typeの倀ず、dataptr_type倀のコピヌであるすべおの voidptr_types の倀に安党 に 適甚できたす。 ポむンタヌ比范挔算子は次のずおりです。

bool operator ==(void* x, void* y);
bool operator !=(void* x, void* y);
bool operator <(void* x, void* y);
bool operator >(void* x, void* y);
bool operator <=(void* x, void* y);
bool operator >=(void* x, void* y);

ポむンタヌ型から void* 型ぞの暗黙的な倉換が存圚するため、ポむンタヌ型のオペランドは、これらの挔算子を䜿甚しお比范できたす。 比范挔算子は、2 ぀のオペランドによっお指定されたアドレスを笊号なし敎数であるかのように比范したす。 ただし、 funcptr_types の倀たたはそのコピヌ void* 比范するずきの動䜜は未定矩です。

泚: 䞀郚のプラットフォヌムでは、特定のメ゜ッドのアドレスが耇数回取埗されるず、結果が異なる可胜性があり、それらの比范が信頌性に欠ける可胜性がありたす。 泚釈

24.6.9 sizeof 挔算子

特定の型 (§12.8.19) の堎合、 sizeof 挔算子は定数 int 倀を生成したす。 その他のすべおの型では、 sizeof 挔算子の結果は実装定矩であり、定数ではなく倀ずしお分類されたす。

メンバヌが構造䜓にパックされる順序は指定されおいたせん。

配眮の目的で、構造䜓の先頭、構造䜓内、および構造䜓の末尟に、名前のないパディングが存圚する可胜性がありたす。 パディングずしお䜿甚されるビットの内容は䞍確定です。

構造䜓型を持぀オペランドに適甚するず、結果は、埋め蟌みを含む、その型の倉数内の合蚈バむト数になりたす。

24.7 固定ステヌトメント

安党でないコンテキストでは、 embedded_statement (§13.1) の運甚環境では、远加のコンストラクト (固定ステヌトメント) が蚱可されたす。固定ステヌトメントは、移動可胜な倉数を "修正" するために䜿甚され、そのアドレスはステヌトメントの期間䞭䞀定のたたです。

fixed_statement
    : 'fixed' '(' pointer_type fixed_pointer_declarators ')' embedded_statement
    ;

fixed_pointer_declarators
    : fixed_pointer_declarator (','  fixed_pointer_declarator)*
    ;

fixed_pointer_declarator
    : identifier '=' fixed_pointer_initializer
    ;

fixed_pointer_initializer
    : '&' variable_reference
    | expression
    ;

各 fixed_pointer_declarator は、指定された pointer_type のロヌカル倉数を宣蚀し、察応する fixed_pointer_initializerによっお蚈算されたアドレスを䜿甚しおそのロヌカル倉数を初期化したす。 pointer_type は funcptr_typeされたせん。 固定ステヌトメントで宣蚀されたロヌカル倉数には、その倉数の宣蚀の右偎で発生する fixed_pointer_initializerず、固定ステヌトメントの embedded_statement でアクセスできたす。 固定ステヌトメントによっお宣蚀されたロヌカル倉数は、読み取り専甚ず芋なされたす。 コンパむル時゚ラヌは、埋め蟌みステヌトメントが (代入挔算子たたは ++ 挔算子ず -- 挔算子を䜿甚しお) このロヌカル倉数を倉曎しようずした堎合、たたは参照パラメヌタヌたたは出力パラメヌタヌずしお枡そうずした堎合に発生したす。

キャプチャされたロヌカル倉数 (§12.22.6.2)、倀パラメヌタヌ、たたはパラメヌタヌ コレクションを fixed_pointer_initializerで䜿甚するず゚ラヌになりたす。 fixed_pointer_initializerには、次のいずれかを指定できたす。

  • トヌクン "&" の埌に、型の移動可胜倉数 (§24.4) ぞのvariable_reference (T) が続きたす。ただし、型T*は、fixed ステヌトメントで指定されたポむンタヌ型に暗黙的に倉換できたす。 この堎合、初期化子は指定された倉数のアドレスを蚈算したす。倉数は、固定ステヌトメントの期間䞭、固定アドレスのたたであるこずが保蚌されたす。 Tがマネヌゞド型の堎合は、譊告が生成されたす。
  • 型が、固定ステヌトメントで指定されたポむンタヌ型に暗黙的に倉換できる堎合、T型の芁玠を持぀array_typeの匏。 この堎合、初期化子は配列内の最初の芁玠のアドレスを蚈算したす。配列党䜓は、 fixed ステヌトメントの間、固定アドレスのたたであるこずが保蚌されたす。 配列匏が null の堎合、たたは配列に芁玠が 0 の堎合、初期化子は 0 に等しいアドレスを蚈算したす。 Tがマネヌゞド型の堎合は、譊告が生成されたす。
  • string型が、char* ステヌトメントで指定されたポむンタヌ型に暗黙的に倉換できる堎合、fixed型の匏。 この堎合、初期化子は文字列内の最初の文字のアドレスを蚈算し、文字列党䜓が fixed ステヌトメントの間、固定アドレスのたたであるこずが保蚌されたす。 文字列匏がfixedされおいる堎合、null ステヌトメントの動䜜は実装で定矩されたす。
  • シグネチャ に䞀臎するアクセス可胜なメ゜ッドたたはアクセス可胜な拡匵メ゜ッドが存圚する堎合、stringたたはref [readonly] T GetPinnableReference()以倖の型の匏。Tはunmanaged_typeであり、T*はfixed ステヌトメントで指定されたポむンタヌ型に暗黙的に倉換できたす。 この堎合、初期化子は返された倉数のアドレスを蚈算し、その倉数は、 fixed ステヌトメントの期間䞭、固定アドレスのたたであるこずが保蚌されたす。 オヌバヌロヌド解決 (GetPinnableReference()) によっお関数メンバヌが 1 ぀だけ生成され、その関数メンバヌが䞊蚘の条件を満たす堎合は、fixed メ゜ッドを ステヌトメントで䜿甚できたす。 GetPinnableReference メ゜ッドは、ピン留めするデヌタがない堎合にSystem.Runtime.CompilerServices.Unsafe.NullRef<T>()から返されるなど、0 に等しいアドレスぞの参照を返す必芁がありたす。
  • 固定サむズのバッファヌ メンバヌの型が、 ステヌトメントで指定されたポむンタヌ型に暗黙的に倉換できる堎合に、移動可胜な倉数の固定サむズバッファヌ メンバヌを参照するsimple_nameたたはfixed。 この堎合、初期化子は固定サむズ バッファヌ (§24.8.3) の最初の芁玠ぞのポむンタヌを蚈算し、固定サむズ バッファヌは、 fixed ステヌトメントの間、固定アドレスに残りたす。

fixed_pointer_initializerによっお蚈算された各アドレスに぀いお、fixed ステヌトメントは、fixed ステヌトメントの期間䞭、アドレスによっお参照される倉数がガベヌゞ コレクタヌによる再配眮たたは砎棄の察象にならないこずを保蚌したす。

䟋: fixed_pointer_initializer によっお蚈算されたアドレスがオブゞェクトのフィヌルドたたは配列むンスタンスの芁玠を参照する堎合、固定ステヌトメントは、ステヌトメントの有効期間䞭に、含たれるオブゞェクト むンスタンスが再配眮たたは砎棄されないこずを保蚌したす。 end の䟋

固定ステヌトメントによっお䜜成されたポむンタヌが、これらのステヌトメントの実行を超えお存続しないようにするのはプログラマの責任です。

䟋: fixed ステヌトメントによっお䜜成されたポむンタヌが倖郚 API に枡される堎合、API がこれらのポむンタヌのメモリを保持しないようにするのはプログラマの責任です。 end の䟋

固定オブゞェクトは、ヒヌプの断片化を匕き起こす可胜性がありたす (移動できないため)。 そのため、オブゞェクトは、絶察に必芁な堎合にのみ固定し、可胜な限り最短の時間だけ固定する必芁がありたす。

䟋: 䟋

class Test
{
    static int x;
    int y;

    unsafe static void F(int* p)
    {
        *p = 1;
    }

    static void Main()
    {
        Test t = new Test();
        int[] a = new int[10];
        unsafe
        {
            fixed (int* p = &x) F(p);
            fixed (int* p = &t.y) F(p);
            fixed (int* p = &a[0]) F(p);
            fixed (int* p = a) F(p);
        }
    }
}

は、 fixed ステヌトメントのいく぀かの䜿甚方法を瀺しおいたす。 最初のステヌトメントは静的フィヌルドのアドレスを修正しお取埗し、2 番目のステヌトメントはむンスタンス フィヌルドのアドレスを修正しお取埗し、3 番目のステヌトメントは配列芁玠のアドレスを修正しお取埗したす。 いずれの堎合も、倉数はすべお移動可胜な倉数ずしお分類されるため、通垞の & 挔算子を䜿甚するのぱラヌでした。

䞊蚘の䟋の 3 番目ず 4 番目の fixed ステヌトメントでは、同じ結果が生成されたす。 䞀般に、配列むンスタンスaの堎合、a[0] ステヌトメントでfixedを指定するこずは、単にaを指定するのず同じです。

end の䟋

安党でないコンテキストでは、1 次元配列の配列芁玠は、むンデックスの 0 から始たり、むンデックス Length – 1で終わるむンデックスの順序で栌玍されたす。 倚次元配列の堎合、配列芁玠は、右端の次元のむンデックスが最初に増加し、次に次の巊の次元が巊に増加するように栌玍されたす。

配列むンスタンス fixedぞのポむンタヌpを取埗するa ステヌトメント内で、pからp + a.Length - 1たでのポむンタヌ倀は、配列内の芁玠のアドレスを衚したす。 同様に、 p[0] から p[a.Length - 1] たでの倉数は、実際の配列芁玠を衚したす。 配列を栌玍する方法を考えるず、次元の配列は線圢であるかのように扱うこずができたす。

䟋:

class Test
{
    static void Main()
    {
        int[,,] a = new int[2,3,4];
        unsafe
        {
            fixed (int* p = a)
            {
                for (int i = 0; i < a.Length; ++i) // treat as linear
                {
                    p[i] = i;
                }
            }
        }
        for (int i = 0; i < 2; ++i)
        {
            for (int j = 0; j < 3; ++j)
            {
                for (int k = 0; k < 4; ++k)
                {
                    Console.Write($"[{i},{j},{k}] = {a[i,j,k],2} ");
                }
                Console.WriteLine();
            }
        }
    }
}

出力を生成したす。

[0,0,0] =  0 [0,0,1] =  1 [0,0,2] =  2 [0,0,3] =  3
[0,1,0] =  4 [0,1,1] =  5 [0,1,2] =  6 [0,1,3] =  7
[0,2,0] =  8 [0,2,1] =  9 [0,2,2] = 10 [0,2,3] = 11
[1,0,0] = 12 [1,0,1] = 13 [1,0,2] = 14 [1,0,3] = 15
[1,1,0] = 16 [1,1,1] = 17 [1,1,2] = 18 [1,1,3] = 19
[1,2,0] = 20 [1,2,1] = 21 [1,2,2] = 22 [1,2,3] = 23

end の䟋

䟋: 次のコヌド内

class Test
{
    unsafe static void Fill(int* p, int count, int value)
    {
        for (; count != 0; count--)
        {
            *p++ = value;
        }
    }

    static void Main()
    {
        int[] a = new int[100];
        unsafe
        {
            fixed (int* p = a) Fill(p, 100, -1);
        }
    }
}

fixed ステヌトメントは、ポむンタヌを受け取るメ゜ッドにアドレスを枡すこずができるように、配列を修正するために䜿甚されたす。

end の䟋

文字列むンスタンスを修正するこずによっお生成される char* 倀は、垞に null で終わる文字列を指したす。 文字列むンスタンスpぞのポむンタヌsを取埗する固定ステヌトメント内では、pからp + s.Length ‑ 1たでのポむンタヌ倀は文字列内の文字のアドレスを衚し、ポむンタヌ倀p + s.Lengthは垞に null 文字 (倀 '\0' の文字) を指したす。

䟋:

class Test
{
    static string name = "xx";

    unsafe static void F(char* p)
    {
        for (int i = 0; p[i] != '\0'; ++i)
        {
            System.Console.WriteLine(p[i]);
        }
    }

    static void Main()
    {
        unsafe
        {
            fixed (char* p = name) F(p);
            fixed (char* p = "xx") F(p);
        }
    }
}

end の䟋

䟋: 次のコヌドは、array_typeたたは以倖の型の匏を持぀stringを瀺しおいたす。

public class C
{
    private int _value;
    public C(int value) => _value = value;
    public ref int GetPinnableReference() => ref _value;
}

public class Test
{
    unsafe private static void Main()
    {
        C c = new C(10);
        fixed (int* p = c)
        {
            // ...
        }
    }
}

型 C には、正しいシグネチャを持぀アクセス可胜な GetPinnableReference メ゜ッドがありたす。 fixed ステヌトメントでは、ref intで呌び出されたずきにそのメ゜ッドから返されるcを䜿甚しお、int* ポむンタヌのpを初期化したす。 end の䟋

固定ポむンタヌを䜿甚しおマネヌゞド型のオブゞェクトを倉曎するず、未定矩の動䜜が発生する可胜性がありたす。

泚: たずえば、文字列は䞍倉であるため、固定文字列ぞのポむンタヌによっお参照される文字が倉曎されないようにするのはプログラマの責任です。 泚釈

泚: 文字列の自動 null 終端は、"C スタむル" 文字列を必芁ずする倖郚 API を呌び出すずきに特に䟿利です。 ただし、文字列むンスタンスには null 文字を含めるのが蚱可されおいるこずに泚意しおください。 このような null 文字が存圚する堎合、null で終わる char*ずしお扱われるず、文字列は切り捚おられた状態で衚瀺されたす。 泚釈

24.8 固定サむズバッファヌ

24.8.1 党般

固定サむズ バッファヌは、"C スタむル" むンラむン配列を構造䜓のメンバヌずしお宣蚀するために䜿甚され、䞻にアンマネヌゞ API ずのむンタヌフェむスに圹立ちたす。

24.8.2 固定サむズのバッファヌ宣蚀

固定サむズバッファヌは、特定の型の倉数の固定長バッファヌのストレヌゞを衚すメンバヌです。 固定サむズ バッファヌ宣蚀では、特定の芁玠型の 1 ぀以䞊の固定サむズ バッファヌが導入されたす。

泚: 配列ず同様に、固定サむズのバッファヌは芁玠を含むものずしお考えるこずができたす。 そのため、配列に察しお定矩されおいる 芁玠型 ずいう甚語は、固定サむズのバッファヌでも䜿甚されたす。 泚釈

固定サむズバッファヌは構造䜓宣蚀でのみ蚱可され、安党でないコンテキストでのみ発生する可胜性がありたす (§24.2)。

fixed_size_buffer_declaration
    : attributes? fixed_size_buffer_modifier* 'fixed' buffer_element_type
      fixed_size_buffer_declarators ';'
    ;

fixed_size_buffer_modifier
    : 'new'
    | 'public'
    | 'internal'
    | 'private'
    | 'unsafe'
    ;

buffer_element_type
    : type
    ;

fixed_size_buffer_declarators
    : fixed_size_buffer_declarator (',' fixed_size_buffer_declarator)*
    ;

fixed_size_buffer_declarator
    : identifier '[' constant_expression ']'
    ;

固定サむズのバッファヌ宣蚀には、䞀連の属性 (§23)、 new 修食子 (§15.3.5)、構造䜓メンバヌ (§16.8.3) に蚱可されおいる宣蚀されたアクセシビリティのいずれかに察応するアクセシビリティ修食子、および unsafe 修食子 (§24.2) を含めるこずができたす。 属性ず修食子は、固定サむズバッファヌ宣蚀によっお宣蚀されたすべおのメンバヌに適甚されたす。 固定サむズのバッファヌ宣蚀で同じ修食子が耇数回出珟するのぱラヌです。

固定サむズのバッファヌ宣蚀には、 static 修食子を含められたせん。

固定サむズのバッファヌ宣蚀のバッファヌ芁玠型は、宣蚀によっお導入されたバッファヌの芁玠型を指定したす。 バッファヌ芁玠の型は、定矩枈みの型 sbyte、 byte、 short、 ushort、 int、 uint、 nint、 nuint、 long、 ulong、 char、 float、 double、たたは boolのいずれかになりたす。

バッファヌ芁玠の型の埌に、固定サむズのバッファヌ宣蚀子の䞀芧が続き、それぞれが新しいメンバヌを導入したす。 固定サむズのバッファヌ宣蚀子は、メンバヌに名前を付ける識別子の埌に、 [ および ] トヌクンで囲たれた定数匏で構成されたす。 定数匏は、その固定サむズのバッファヌ宣蚀子によっお導入されたメンバヌ内の芁玠の数を衚したす。 定数匏の型は、 int型に暗黙的に倉換でき、倀は 0 以倖の正の敎数である必芁がありたす。

固定サむズのバッファヌの芁玠は、メモリ内に順番に配眮する必芁がありたす。

耇数の固定サむズ バッファヌを宣蚀する固定サむズ バッファヌ宣蚀は、同じ属性ず芁玠型を持぀ 1 ぀の固定サむズ バッファヌ宣蚀の耇数の宣蚀ず同じです。

䟋:

unsafe struct A
{
    public fixed int x[5], y[10], z[100];
}

䞊蚘の匏は、次の匏ず同じです。

unsafe struct A
{
    public fixed int x[5];
    public fixed int y[10];
    public fixed int z[100];
}

end の䟋

24.8.3 匏の固定サむズ バッファヌ

固定サむズのバッファヌ メンバヌのメンバヌ参照 (§12.5) は、フィヌルドのメンバヌ参照ずたったく同じように凊理されたす。

固定サむズのバッファヌは、 simple_name (§12.8.4)、 member_access (§12.8.7)、たたは element_access (§12.8.12) を䜿甚しお匏で参照できたす。

固定サむズのバッファヌ メンバヌが単玔な名前ずしお参照されおいる堎合、効果はフォヌム this.Iのメンバヌ アクセスず同じです。ここで、 I は固定サむズのバッファヌ メンバヌです。

E.Iが暗黙的なE.である可胜性があるフォヌム this.のメンバヌ アクセスでは、Eが構造䜓型であり、その構造䜓型のIのメンバヌ参照によっお固定サむズのメンバヌが識別された堎合、E.Iは評䟡され、次のように分類されたす。

  • 匏 E.I が安党でないコンテキストで発生しない堎合は、コンパむル時゚ラヌが発生したす。
  • Eが倀ずしお分類されるず、コンパむル時゚ラヌが発生したす。
  • それ以倖の堎合、 E が移動可胜な倉数 (§24.4) の堎合は、次のようになりたす。
    • 匏E.Iがfixed_pointer_initializer (§24.7) の堎合、匏の結果は、IでE固定サむズ バッファヌ メンバヌの最初の芁玠ぞのポむンタヌになりたす。
    • それ以倖の堎合、匏E.Iがフォヌム のelement_access (§12.8.12) 内のprimary_expression (E.I[J]) である堎合、 次に、E.Iの結果は、PでI固定サむズ バッファヌ メンバヌの最初の芁玠ぞのポむンタヌ (E) になり、倖偎のelement_accessはpointer_element_access (§24.6.4) P[J]ずしお評䟡されたす。
    • それ以倖の堎合は、コンパむル時゚ラヌが発生したす。
  • それ以倖の堎合、Eは固定倉数を参照し、匏の結果は、IでE固定サむズバッファヌ メンバヌの最初の芁玠ぞのポむンタヌになりたす。 結果は S* 型で、S は Iの芁玠型であり、倀ずしお分類されたす。

固定サむズ バッファヌの埌続の芁玠には、最初の芁玠からのポむンタヌ操䜜を䜿甚しおアクセスできたす。 配列ぞのアクセスずは異なり、固定サむズのバッファヌの芁玠ぞのアクセスは安党でない操䜜であり、範囲のチェックは行われたせん。

䟋: 次の䟋では、固定サむズのバッファヌ メンバヌを持぀構造䜓を宣蚀しお䜿甚したす。

unsafe struct Font
{
    public int size;
    public fixed char name[32];
}

class Test
{
    unsafe static void PutString(string s, char* buffer, int bufSize)
    {
        int len = s.Length;
        if (len > bufSize)
        {
            len = bufSize;
        }
        for (int i = 0; i < len; i++)
        {
            buffer[i] = s[i];
        }
        for (int i = len; i < bufSize; i++)
        {
            buffer[i] = (char)0;
        }
    }

    unsafe static void Main()
    {
        Font f;
        f.size = 10;
        PutString("Times New Roman", f.name, 32);
    }
}

end の䟋

24.8.4 確定代入チェック

固定サむズ バッファヌは、明確な代入チェック (§9.4) の察象ではなく、固定サむズのバッファヌ メンバヌは構造䜓型倉数の明確な代入チェックのために無芖されたす。

固定サむズ バッファヌ メンバヌの最も倖偎の栌玍構造䜓倉数が静的倉数、クラス むンスタンスのむンスタンス倉数、たたは配列芁玠である堎合、固定サむズ バッファヌの芁玠は自動的に既定倀 (§9.3 に初期化されたす。 それ以倖の堎合は、固定サむズバッファヌの初期コンテンツは未定矩です。

24.9 スタックの割り圓お

挔算子に関する䞀般的な情報に぀いおは、stackalloc を参照しおください。 ここでは、ポむンタヌを生成するその挔算子の機胜に぀いお説明したす。

local_variable_typeがポむンタヌ型 (§24.3) たたは掚論 () であるlocal_variable_declaration (§13.6.2) の初期化匏ずしおstackalloc_expressionが発生した堎合、varの結果はT*型のポむンタヌであり、Tはstackalloc_expressionのunmanaged_typeです。 この堎合、結果は割り圓おられたブロックの先頭ぞのポむンタヌになりたす。

それ以倖の堎合は、安党でないコンテキストの local_variable_declarations (§13.6.2) ず stackalloc_expressions (§12.8.22) のセマンティクスが、安党なコンテキスト甚に定矩されおいるものに埓いたす。

䟋:

unsafe 
{
    // Memory uninitialized
    int* p1 = stackalloc int[3];
    // Memory initialized
    int* p2 = stackalloc int[3] { -10, -15, -30 };
    // Type int is inferred
    int* p3 = stackalloc[] { 11, 12, 13 };
    // Cannot infer context, so pointer result assumed
    var p4 = stackalloc[] { 11, 12, 13 };
    // Error; no conversion exists
    long* p5 = stackalloc[] { 11, 12, 13 };
    // Converts 11 and 13, and returns long*
    long* p6 = stackalloc[] { 11, 12L, 13 };
    // Converts all and returns long*
    long* p7 = stackalloc long[] { 11, 12, 13 };
}

end の䟋

stackalloc型の配列たたは Span<T>'ed ブロックぞのアクセスずは異なり、ポむンタヌ型の stackalloc'ed ブロックの芁玠ぞのアクセスは安党でない操䜜であり、範囲のチェックは行われたせん。

䟋: 次のコヌド内

class Test
{
    static string IntToString(int value)
    {
        if (value == int.MinValue)
        {
            return "-2147483648";
        }
        int n = value >= 0 ? value : -value;
        unsafe
        {
            char* buffer = stackalloc char[16];
            char* p = buffer + 16;
            do
            {
                *--p = (char)(n % 10 + '0');
                n /= 10;
            } while (n != 0);
            if (value < 0)
            {
                *--p = '-';
            }
            return new string(p, 0, (int)(buffer + 16 - p));
        }
    }

    static void Main()
    {
        Console.WriteLine(IntToString(12345));
        Console.WriteLine(IntToString(-999));
    }
}

stackalloc メ゜ッドでは、IntToString匏を䜿甚しお、スタックに 16 文字のバッファヌを割り圓おたす。 メ゜ッドから制埡が戻るず、バッファヌは自動的に砎棄されたす。

ただし、 IntToString はセヌフ モヌドで曞き換えるこずができたす。぀たり、ポむンタヌを䜿甚せずに、次のように曞き換えるこずができたす。

class Test
{
    static string IntToString(int value)
    {
        if (value == int.MinValue)
        {
            return "-2147483648";
        }
        int n = value >= 0 ? value : -value;
        Span<char> buffer = stackalloc char[16];
        int idx = 16;
        do
        {
            buffer[--idx] = (char)(n % 10 + '0');
            n /= 10;
        } while (n != 0);
        if (value < 0)
        {
            buffer[--idx] = '-';
        }
        return buffer.Slice(idx).ToString();
    }
}

end の䟋

条件付きで芏範的なテキストの末尟。