ポインター レイアウト
ポインター レイアウトは、構造または配列のポインターを表します。
pointer_layout<>
Pointer_layout<> フィールドは、後で説明するように、FC_PP FC_PAD形式文字の後に 1 つ以上のポインターの説明が続き、FC_END形式文字で終わる形式の文字で構成されます。
FC_PP
FC_PAD
{ pointer_instance_layout<> }*
FC_END
Pointer_instance_layout<> フィールドは、ポインターの単一または複数のインスタンスを記述する書式指定文字列です。 これらの記述子では、次のフィールドが使用されます。
offset_in_memory
メモリ内のポインターの位置への符号付きオフセット。 構造内に存在するポインターの場合、このオフセットは構造の終端 (準拠構造の不適合部分の終端) からの負のオフセットです。配列の場合、オフセットは配列の先頭から取得されます。
offset_in_buffer
バッファー内のポインターの位置への符号付きオフセット。 構造内に存在するポインターの場合、このオフセットは構造の終端 (準拠構造の不適合部分の終端) からの負のオフセットです。配列の場合、オフセットは配列の先頭から取得されます。
offset_to_array
外側の構造から、ポインターが処理されている埋め込み配列へのオフセット。 最上位の配列の場合、このフィールドは常に 0 になります。
イテレーション
同じレイアウト<> が記述されているポインターの合計数。
increment
REPEAT 中の連続するポインター間のインクリメント。
number_of_pointers
繰り返しインスタンス内の異なるポインターの数。
pointer_description
ポインターの説明。
すべてのポインター インスタンス レイアウトでは、次の単一 pointer_instance<8> が使用されます。
offset_to_pointer_in_memory<2>
offset_to_pointer_in_buffer<2>
pointer_description<4>
インスタンス記述子は次に示されます。
シンプル型へのポインターの単一インスタンス:
FC_NO_REPEAT FC_PAD
pointer_instance<8>
固定リピートポインター:
FC_FIXED_REPEAT FC_PAD
iterations<2>
increment<2>
offset_to_array<2>
number_of_pointers<2>
{ pointer_instance<8> }*
変数リピートポインター:
FC_VARIABLE_REPEAT (FC_FIXED_OFFSET | FC_VARIABLE_OFFSET)
increment<2>
offset_to_array<2>
number_of_pointers<2>
{ pointer_instance<8> }*
固定リピートポインター インスタンスと変数リピートポインター インスタンスの場合、リピートインスタンス内の各ポインターのオフセットとポインターの説明のセットがあります。
ポインター レイアウトの設計に関する問題
このセクションでは、準拠構造と埋め込みポインターの処理に関連する問題について説明します。 問題は、コンパイラが何らかの冗長性を持つ構造と配列のポインター レイアウトを生成することです。 これは有益です。情報が有用であるため、たとえば、準拠構造は、1 つのポインター レイアウトをウォークして、構造および、準拠構造の一部である整合配列からのすべてのポインターにサービスを提供できます。 ただし、一部の埋め込み状況では、NDR エンジンが適切なシーケンス内のすべてのポインター レイアウトを処理し、各ポインターを 1 回だけ処理するために追加の作業を実行する必要があります。
コンパイラによって生成される内容
このセクションで説明するすべてのオブジェクトにはポインターがあるため、たとえば、準拠構造には、構造部分と配列要素のポインターがあります。 要素は、ポインターを持つシンプル構造です。
一致する構造、単一レベル
準拠記述子には、構造と配列の両方から、すべてのポインターが記述される PP 部分があります。 メンバー リストには、ポインターの代わりに FC_LONG があります。 CARRAY 配列記述子には、embedded_complex を使用する要素があり、ポインター記述子はありません。 要素には、依然として単一ポインター記述子があります。 ポインター レイアウトは、準拠構造とシンプル構造記述子のメンバー レイアウトの前にあります。
準拠構造で、2 つ以上のレベル
PP 記述には、すべてのレベルからのポインターがあります。 これは、内部準拠構造と同じ配列記述を再利用します。 メンバー リストには、ポインターの代わりに FC_LONG があります。 埋め込み構造は、埋め込み複合体を使用して行います。 準拠構造記述子は、そのまま再利用されます。 構造のフラット部分のサイズも完全に出てくるので、最上位レベルの構造のサイズには埋め込み構造のフラット サイズが含まれます。
複合構造、単一レベル
ポインター メンバーは、FC_POINTER でマークされます。 ポインター のレイアウトが簡略化され、リストの各FC_POINTER エントリに対してポインター記述子 (4 バイト) が存在します。 ポインター レイアウトは、メンバー ウォークと並行してウォークされます。つまり、FC_POINTER によって、次のポインター記述が処理されます。 CARRAY 配列には、埋め込み複合関数を使用して、配列のすべての記述子と要素を含むポインター レイアウトがあります。 要素記述子が再利用されます。 構造の平坦部分のサイズが完成します。つまり、最上位レベルの構造のフラット サイズには、埋め込み構造のフラット サイズが含まれます。 メンバー レイアウトは、複合構造のポインター レイアウトの前にあります。
したがって、整合配列記述の生成は、それが整合配列の内部にある配列であるか、または複合構造内にあるかに応じて異なります。
複雑な構造、2 つ以上のレベル、複合内の複合
最上位の複合構造にはメンバー ポインターがあり、埋め込み複合構造にはメンバー ポインターがあります。 準拠構造記述子が再利用されます。 一番上の配列記述子は、埋め込み構造の再利用された配列です。
埋め込まれた準拠構造を持つ複合構造
Top=level 準拠構造にはメンバー ポインターがあります。 準拠構造記述子は、そのまま再利用されます。 配列記述子は、埋め込まれた準拠構造から再利用されます。つまり、配列記述子にはポインターがありません。 要素にはポインター記述子があります。
ポインターを持つ構造の配列
ポインターを持つシンプル構造の配列は、配列のサイズに応じて SMFARRAY または CARRAY として生成されますが、どちらの場合も、完全なポインター レイアウト (FIXED_REPEAT または VARIABLE_REPEAT) があります。 ポインター レイアウトは、メンバー レイアウトの前に配置されます。
ポインターを持つ複合構造の配列は、固定またはサイズに関係なく BOGUS_ARRAY として生成され、どちらの場合もポインター レイアウトはありません。
NDR エンジンの機能
このセクションでは、NDR エンジンの動作について説明します。
マーシャリング パス
準拠構造と埋め込まれた準拠構造。
最上位の構造は、単一レベルの構造のように動作します。
整合配列を持つ埋め込まれた複合構造
任意の複合構造は、外側の構造を複合構造に強制します。 埋め込み構造は配列をマーシャリングしません。 すべての構造は常に、メンバーをマーシャリングするだけで埋め込みポインターを通過し、メンバーはFC_POINTERになります。
準拠構造を持つ複合構造
埋め込まれた最上位の準拠構造は、整合配列とすべてのポイントをマーシャリングします。 NDR エンジンは、入れ子になったより深い準拠構造が存在する場合、その構造に降りることはありません。これにより、埋め込みオブジェクトのマーシャリングに関する限り、準拠構造がリーフ オブジェクトであるため、ソリューションが簡略化されます。 最上位の複合構造は、配列のマーシャリングをスキップします。
パスのマーシャリング解除、バッファー処理、解放
マーシャリング解除はマーシャリングと対称です。複合構造に対して最初に実行する操作は、NdrComplexStructBufferSize 関数を呼び出すことによって、バッファー内のポイント先の位置を見つけることです。 次に、ポイントを並列にマーシャリング解除し、ポイントを正しくマーシャリング解除するための同じスキームを使用できるようにします。 サイズの大きさのオブジェクトと共用体に関する混乱はありません。メモリ イメージは、バッファーの内容のためだけに、サイズの大きさのオブジェクトと共用体には使用しないでください。
マーシャリングとマーシャリング解除を正しく実行するために使用されるフラグは、ポイントが正確に 1 回ウォークしていることを確認するために、バッファー処理と解放の場合と同じ方法で使用されます。
エンディアン パス
最初はエンディアンパスはマーシャリング/アンマーシャリングにやや似ています。複合構造を処理するには、2 つのパスが必要です。 最初のパスはフラット部分を変換し、バッファー内のポイントの位置を検索します。これは、bufsizing がマーシャリング解除のためにこの操作を実行する方法と同様です。 2 番目のパスは、ポイントを変換します。
エンディアン パスは、次の方法で異なります。リーフ メンバーまたは要素がシンプル型になるまで、すべての構造とすべてのメンバーをステップ実行する必要があります。 これはマーシャリングとは異なります。例えば、非マーシャリングでは、その問題のために、準拠構造に埋め込まれた準拠構造、または準拠構造の任意のメンバーを処理する必要はありません。 もう 1 つの問題は、変換が冪等操作でないため、マーシャリング解除パスが何らかの部分のマーシャリング解除を害なくやり直す可能性がある一方で、変換は厳密に任意の単純な型ごとに 1 回実行する必要があるということです。
したがって、エンディアン アルゴリズムは次のように要約できます。 NDR には、最上位の準拠構造の概念と、必要に応じてマークするフラグがあります。 平坦部を変換してポイント対象の位置を取得するなどの、初回ウォークにおいては、この概念は使用されません。 NDR は、すべてのレベルの構造のフラット部分を降下し、ポインター処理に挑戦することはありません。 最後に、NDR は最上位レベルで配列をフラット変換します。
2 回目のウォークでは、このフラグを使用して、埋め込まれたポインターのパスをマークして、準拠構造のレベルが深くなることを防いだら、最も準拠した構造をマークします。 この方法では、フラグは一般的なマーシャリング/マーシャリング解除動作を強制します。これは、より深いレベルの準拠構造へ降りることを避けるためです。
整合配列を持つ複合構造の 2 番目のパスは、次のように機能します。複合構造は一般的な方法で動作します。つまり、より深いレベルでは、準拠するサイズや整合配列を参照したりスキップしたりすることは決してなく、配列に触れることなくメンバーをウォークするだけです。
準拠構造を持つ複合構造の場合、準拠構造は最上位レベルかどうか、および複合構造内にあるかどうかを認識する必要があります。 配列のフラット部分は、最上位の準拠構造によって処理されます。 2 番目のパスでは、最上位の準拠構造はフラット部分をスキップし、ポインター のレイアウトを通過して戻ります。 最も複合構造は、そのフラット部分をスキップし、ポインターのレイアウトもスキップします。
エンディアン ウォークの堅牢な側面
エンディアンは、通常のバッファー外状態のチェックをウォークし、相関のない性質の他のチェックを実行します。 関連付けられた値 (サイズ変更引数と適合サイズなど) を目的としたチェックは、この手順を使用して実行できません。後でマーシャリングを解除するときに実行されます。