C#のバックグラウンドがあります。私は、Cのような低レベル言語の初心者です。
C#では、struct
のメモリはデフォルトでコンパイラによってレイアウトされます。コンパイラは、データフィールドを並べ替えたり、フィールド間に追加のビットを暗黙的に埋め込むことができます。そのため、正確なレイアウトのためにこの動作をオーバーライドするには、特別な属性を指定する必要がありました。
私の知る限り、Cはデフォルトでstruct
のメモリレイアウトを並べ替えたり整列したりしません。しかし、見つけるのが非常に難しい小さな例外があると聞きました。
Cのメモリレイアウト動作とは何ですか?何を並べ替える必要がありますか?
Cでは、コンパイラーはすべてのプリミティブ型のアライメントを指示できます。通常、配置は型のサイズです。しかし、それは完全に実装固有です。
すべてのオブジェクトが適切に整列されるように、パディングバイトが導入されています。並べ替えはできません。
おそらくすべてのリモートの最新コンパイラーは#pragma pack
これは、パディングの制御を許可し、ABIに準拠するためにそれをプログラマに任せます。 (ただし、これは厳密に非標準です。)
C99§6.7.2.1から:
12構造体または共用体オブジェクトの各非ビットフィールドメンバーは、そのタイプに適した実装定義の方法で整列されます。
13構造体オブジェクト内では、非ビットフィールドメンバーとビットフィールドが存在するユニットのアドレスは、宣言された順に増加します。適切に変換された構造体オブジェクトへのポインターは、その最初のメンバー(またはそのメンバーがビットフィールドである場合は、そのメンバーが存在するユニット)を指し、逆も同様です。構造体オブジェクト内には無名のパディングがありますが、その先頭にはありません。
実装固有ですが、実際にはルール(_#pragma pack
_などがない場合)は次のとおりです。
sizeof(T)
バイトのアライメントが必要です。したがって、次の構造体が与えられます:
_struct ST
{
char ch1;
short s;
char ch2;
long long ll;
int i;
};
_
ch1
_はオフセット0ですs
オフセット2ch2
_は、sの直後のオフセット4にありますll
オフセット8i
は、llの直後のオフセット16にありますしたがって、sizeof(ST)
は24です。
パディングを回避するためにメンバーを再配置することにより、16バイトに減らすことができます。
_struct ST
{
long long ll; // @ 0
int i; // @ 8
short s; // @ 12
char ch1; // @ 14
char ch2; // @ 15
} ST;
_
データ構造の整列ウィキペディアの記事 を読むことから始めて、データの整列の理解を深めてください。
wikipediaの記事 から:
データの整列とは、Wordサイズの倍数に等しいメモリオフセットにデータを配置することを意味します。これにより、CPUがメモリを処理する方法によりシステムのパフォーマンスが向上します。データを整列させるには、最後のデータ構造の終わりと次のデータ構造の始まりであるデータ構造のパディングの間に無意味なバイトを挿入する必要があるかもしれません。
GCCドキュメントの 6.54.8 Structure-Packing Pragmas から:
Microsoft Windowsコンパイラとの互換性のために、GCCは一連の#pragmaディレクティブをサポートします。#pragmaディレクティブは、構造体(ゼロ幅ビットフィールド以外)、ユニオン、およびその後に定義されるクラスのメンバーの最大アライメントを変更します。以下のn値は常に2の小さな累乗である必要があり、バイト単位で新しいアライメントを指定します。
#pragma pack(n)
は、単に新しい配置を設定するだけです。#pragma pack()
は、コンパイルを開始したときに有効だったアライメントにアライメントを設定します(コマンドラインオプション-fpack-struct [=]も参照してください。コード生成オプションを参照)。#pragma pack(Push[,n])
は、内部スタックに現在のアライメント設定をプッシュし、オプションで新しいアライメントを設定します。#pragma pack(pop)
は、内部スタックの最上部に保存されているものにアライメント設定を復元します(そしてそのスタックエントリを削除します)。#pragma pack([n])
はこの内部スタックに影響しないことに注意してください。したがって、#pragma pack(Push)
の後に複数の#pragma pack(n)
インスタンスが続き、単一の#pragma pack(pop)
でファイナライズされる可能性があります。いくつかのターゲット、例えばi386およびpowerpcは、文書化された
__attribute__ ((ms_struct))
として構造をレイアウトするms_struct#pragma
をサポートします。
#pragma ms_struct on
は、宣言された構造のレイアウトをオンにします。#pragma ms_struct off
は、宣言された構造のレイアウトをオフにします。#pragma ms_struct reset
はデフォルトのレイアウトに戻ります。