配置)するかという問題があります。通常、メモリ上のレイアウトがどうなっているのかをプログラマーが気にする必要はありません。大体はコンパイラーが最適な仕事をしてくれます。コードとの相互運用です)。そこで、プログラミング言語によってはレイアウトをカスタマイズするための機能を提供しているものもあります。C#では、クラスと構造体に対してレイアウトのカスタマイズ機能を提供しています。StructLayout属性を付けることでカスタマイズ可能です。整列、調整)について知る必要があります。一般に、メモリの読み書きは、アドレスが4の倍数や8の倍数になっている方が高速です。(1命令で読み出せるのは倍数ピッタリの場所だけなCPUもあります。最悪、2命令で隣り合った場所を読み込んで、繋ぎなおすような処理が必要になります。)そこで、多くのプログラミング言語で、アドレスがきれいな倍数になるように、フィールドとフィールドの間に隙間を空けたり、フィールドを並べ替えたりしています。この、所定の倍数の位置にフィールドを並べる処理をアラインメントと呼びます。以下のような構造体を書いたとします。(long型)が8バイトのデータです。レイアウトは以下のようになります。フィールドすべてが8の倍数アドレスに並ぶように、8バイト間隔でフィールドが並びます。末尾にも、全体が8の倍数になるように未使用領域が追加されます。C#でレイアウトを調べてみるC#でも、unsafeコードを使えば、構造体のレイアウトを調べることができます。以下のように、ポインターを使って、構造体の先頭と、各フィールドのアドレスの差を見れば、レイアウトがわかります。}}ただし、1つ注意があります。C#では、たとえunsafeコード内であっても、参照型のアドレスは取れないようになっています。そのため、参照型や、参照型を含んだ構造体の場合はレイアウトを調べられません。}}レイアウトの指定C#では、StructLayout属性(System.Runtime.InteropServices名前空間)を付けることで、レイアウト方式をカスタマイズ可能です。以下の3種類のレイアウト方式を選択できます。複合型の作者が明示的に位置を指定するちなみに、何も指定しない場合、構造体はSequentialレイアウト、クラスはAutoレイアウトになります。フィールドとフィールドに何バイトの間隔を空けるか(Pack)を指定することもできます。SequentialレイアウトSequentialレイアウトでは、複合型のフィールドは宣言した順序通りにレイアウトされます。StructLayout属性の引数に、LayoutKind.Sequentialを渡します。C;}アラインメントの説明で挙げたのと同じ絵になりますが、このコードは以下のようなレイアウトになります。構造体では、特に何も指定しないとSequentialレイアウトになります。順序通りに並べるとコンパイラーごとの差異が生まれにくく、相互運用がしやすいからでしょう(構造体はネイティブコードとの相互運用に使うことが結構多い)。64ビット)です(それが一番高速になる可能性が高い)。Packを明示的に指定したい場合には、以下のように、StructLayout属性のPackプロパティに数値を与えます。C;}これで、以下のようなレイアウトになります。AutoレイアウトAutoレイアウトでは、コンパイラー裁量でフィールドの順序変更を許します。StructLayout属性の引数に、LayoutKind.Autoを渡します。隙間をより小さい型で埋めたりして、型のサイズが最小になるように並び替えが行われます。以下のような構造体を書いた場合を考えます。C;}この場合、byte型のフィールド2つを固めて後ろに持っていくことで、long型のBのアラインメントは揃えつつ、構造体のサイズを小さくします。結果、以下のような12バイトのレイアウトになります。ちなみに、クラスでは、特に何も指定しないとAutoレイアウトになります。ExplicitレイアウトStructLayout属性の引数に、LayoutKind.Explicitを指定して、フィールドにFieldOffset属性を付けることで、フィールドの位置を明示的に指定することができます。以下のような構造体を書いた場合を考えます。C;}以下のような変な隙間が空いたレイアウトになります。フィールドの位置を重ねるExplicitレイアウトを使うと、複数のフィールドの位置を重ねることもできます。C言語のunionのようなことができます。以下のようなことができます。}}78563412int型のフィールドNに書き込んだ結果を、1バイト1バイト、個別に取り出しています。ちなみに、下位バイト(この例では78)が先頭(フィールドA)に来るか末尾(フィールドD)に来るかはCPUによります(「エンディアン(endian)」と言います)。endianと言います。たちが悪い悪用ができたりします。本来あり得ない値を作ったりできます。通常、C#のbool型がtrueかfalseの2つの値しかとりません。別の型のフィールドと重ねて、無理やり上書きすることで、他の値にできます。以下のようなコードが書けます。0の数値になっていることが分かります。それ以外の数値を指定すると、switchの飛び先が変わります。ちなみに、0以外の数値は、真偽判定(ifステートメントの条件式内とか)で使うとtrue扱いになります。ToStringの結果もTrueです。switchステートメントでだけ変な結果を起こせます。値と参照を重ねるExplicitレイアウトには1つ制限があります。値型のフィールドと参照型のフィールドを同じ位置に重ねてレイアウトすることはできません。エラーにはならず、実行時エラーです。(C#の制限ではなくて、.NETランタイムの制限なので、実行時にしかエラーを拾えない。)例えば、以下のようなコードを書くと、TypeLoadExceptionが発生します。コレクションの都合です。コレクションは、参照をたどって誰からも参照されていないオブジェクトを探索するわけですが、ここで、本当に参照なのかどうかがわからないものがあると探索に支障をきたします。値と参照が重なっていると、この状態が生まれます。ちなみに、プログラミング言語によっては、同じメモリ領域に値と参照をどちらでも格納できるものもあります。いう言語の場合は、以下のいずれかの処理を行っています。まで気兼ねなくご連絡ください。ついて運営者について。