ポインター レイアウトは、構造体または配列のポインターを表します。
pointer_layout<>
pointer_layout<> フィールドは、後で説明するように、FC_PP FC_PAD形式文字の後に 1 つ以上のポインターの説明が続き、FC_END形式文字で終わる形式の文字で構成されます。
FC_PP
FC_PAD
{ pointer_instance_layout<> }*
FC_END
pointer_instance_layout<> フィールドは、ポインターの 1 つまたは複数のインスタンスを記述する書式指定文字列です。 これらの記述子では、次のフィールドが使用されます。
offset_in_memory
メモリ内のポインターの位置への符号付きオフセット。 構造体内に存在するポインターの場合、このオフセットは構造体の末尾 (準拠構造体の不適合部分の終点) からの負のオフセットです。配列の場合、オフセットは配列の先頭から取得されます。
offset_in_buffer
バッファー内のポインターの位置への符号付きオフセット。 構造体に存在するポインターの場合、このオフセットは構造体の末尾 (準拠構造体の不適合部分の末尾) からの負のオフセットです。配列の場合、オフセットは配列の先頭から取得されます。
offset_to_array
外側の構造体から、ポインターが処理されている埋め込み配列へのオフセット。 最上位の配列の場合、このフィールドは常に 0 になります。
イテレーション
同じレイアウトを持つポインターの合計数<> 説明します。
インクリメント
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があります。 埋め込み構造は、埋め込み複合体を使用して行います。 準拠構造体記述子は、as-is再利用されます。 構造のフラット部分のサイズも完全に出てくるので、最上位レベルの構造体のサイズには埋め込み構造のフラット サイズが含まれます。
複雑な構造、単一レベル
ポインター メンバーは、FC_POINTERでマークされます。 ポインター のレイアウトが簡略化され、リストの各FC_POINTERエントリに対してポインター記述子 (4 バイト) が存在します。 ポインター レイアウトは、メンバー ウォークと並行してウォークされます。つまり、FC_POINTERによって、次のポインター記述が処理されます。 CARRAY 配列には、埋め込み複合関数を使用して、配列のすべての記述子と要素を含むポインター レイアウトがあります。 要素記述子が再利用されます。 構造の平坦部分のサイズは完全に出てくる。つまり、最上位レベルの構造体のフラット サイズには、埋め込み構造体のフラット サイズが含まれます。 メンバー レイアウトは、複雑な構造体のポインター レイアウトの前にあります。
したがって、適合する配列記述の生成は、それが適合構造の内部にある配列であるか、または複雑な構造内にあるかに応じて異なります。
複雑な構造、2 つ以上のレベル、複雑な構造
最上位の複合構造体にはメンバー ポインターがあり、埋め込み複合構造体にはメンバー ポインターがあります。 準拠構造体記述子が再利用されます。 一番上の配列記述子は、埋め込み構造体の再利用された配列です。
埋め込まれた適合構造を持つ複雑な構造
Top=level 準拠構造体にはメンバー ポインターがあります。 準拠構造体記述子は、as-is再利用されます。 配列記述子は、埋め込まれた準拠構造体から再利用されます。つまり、配列記述子にはポインターがありません。 要素にはポインター記述子があります。
ポインターを持つ構造体の配列
ポインターを持つ単純構造体の配列は、配列のサイズに応じて 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 番目のパスでは、最上位の準拠構造体はフラット部分をスキップし、ポインター のレイアウトを通過して戻ります。 最も複雑な構造は、そのフラット部分をスキップし、ポインターのレイアウトもスキップします。
エンディアンの堅牢な側面は、
エンディアン ウォークは、通常のバッファー外の状態をチェックし、相関のない性質の他のチェックを実行します。 関連付けられた値 (サイズ変更引数と適合サイズなど) を目的としたチェックは、この手順を使用して実行できません。これらは後でマーシャリングを解除するときに実行されます。