質問
C#の背景があります。私はCのような低レベルの言語の初心者です
C#で、 struct
のメモリは、デフォルトでコンパイラによってレイアウトされています。コンパイラは、データフィールドを再注文したり、フィールド間で追加のビットを暗黙的に装飾したりできます。そのため、正確なレイアウトのためにこの動作をオーバーライドするために、特別な属性を指定する必要がありました。
afaik、cは、 struct
デフォルトで。しかし、私は見つけるのが非常に難しい少しの例外があると聞きました。
Cのメモリレイアウト動作とは何ですか?何を再注文/アライメントする必要がありますか?
解決
Cでは、コンパイラはすべてのプリミティブタイプのある程度のアラインメントを決定することができます。通常、アライメントはタイプのサイズです。しかし、それは完全に実装固有です。
パディングバイトが導入されているため、すべてのオブジェクトが適切に整列されています。並べ替えは許可されていません。
おそらくすべてのリモートで最新のコンパイラが実装されています #pragma pack
これにより、パディングを制御できるようになり、ABIに準拠するためにプログラマーに任せます。 (しかし、それは厳密に非標準です。)
C99§6.7.2.1から:
12構造または組合オブジェクトの各非ビットフィールドメンバーは、そのタイプに適した実装定義された方法で整列されています。
13構造物オブジェクト内では、ビットフィールド以外のメンバーとビットフィールドが存在するユニットには、宣言された順序が増加するアドレスがあります。適切に変換された構造物オブジェクトへのポインターは、最初のメンバーを指します(または、そのメンバーが少しフィールドである場合、その後、それが存在するユニットを)、逆も同様です。構造物オブジェクト内には無名のパディングがあるかもしれませんが、最初はそうではありません。
他のヒント
実装固有ですが、実際にはルールがあります( #pragma pack
または同様)は次のとおりです。
- structメンバーは、宣言された順序で保存されます。 (これは、前述のように、C99規格で必要です。)
- 必要に応じて、各structメンバーの前にパディングが追加され、正しいアライメントを確保します。
- 各プリミティブタイプtには、のアライメントが必要です
sizeof(T)
バイト。
したがって、次の構造を考えると、
struct ST
{
char ch1;
short s;
char ch2;
long long ll;
int i;
};
ch1
オフセット0です- パディングバイトが挿入されて挿入されています...
s
オフセット2ch2
sの直後のオフセット4にあります- 3つのパディングバイトが挿入されて挿入されています...
ll
オフセット8でi
LLの直後にオフセット16です- 全体の構造体が8バイトの倍数になるように、最後に4つのパディングバイトが追加されます。これを64ビットシステムで確認しました。32ビットシステムにより、構造体が4バイトのアライメントを持つことができます。
それで sizeof(ST)
24です。
パディングを避けるためにメンバーを再配置することにより、16バイトに削減できます。
struct ST
{
long long ll; // @ 0
int i; // @ 8
short s; // @ 12
char ch1; // @ 14
char ch2; // @ 15
} ST;
あなたは読むことから始めることができます データ構造アライメントウィキペディアの記事 データの調整をよりよく理解するため。
から ウィキペディアの記事:
データアライメントとは、データを単語サイズの倍数に等しいメモリオフセットに配置することを意味します。これにより、CPUがメモリを処理する方法により、システムのパフォーマンスが向上します。データを整列するには、最後のデータ構造の端と次のデータ、つまりデータ構造のパディングの開始の間に意味のないバイトを挿入する必要がある場合があります。
から 6.54.8構造パッキングプラグマ GCCドキュメントの:
Microsoft Windowsコンパイラとの互換性のために、GCCは、構造のメンバー(ゼロ幅ビットフィールド以外)、組合、およびその後定義されたクラスの最大整列を変更する#Pragmaディレクティブのセットをサポートします。以下のN値は常に2つの小さなパワーである必要があり、バイトの新しいアライメントを指定します。
#pragma pack(n)
新しいアライメントを設定するだけです。#pragma pack()
コンパイルが開始されたときに有効なものにアラインメントを設定します(コマンドラインオプション-FPACK -struct [=]も参照してください。コードGENオプションを参照)。#pragma pack(push[,n])
現在のアライメント設定を内部スタックに押してから、オプションで新しいアライメントを設定します。#pragma pack(pop)
アライメント設定は、内部スタックの上部に保存されているものに復元します(そして、そのスタックエントリを削除します)。ご了承ください#pragma pack([n])
この内部スタックに影響を与えません。したがって、持つことが可能です#pragma pack(push)
続いて複数#pragma pack(n)
インスタンスとシングルで完成しました#pragma pack(pop)
.I386とPowerPCなどの一部のターゲットは、MS_STRUCTをサポートしています
#pragma
文書化されたように構造をレイアウトします__attribute__ ((ms_struct))
.
#pragma ms_struct on
宣言された構造のレイアウトをオンにします。#pragma ms_struct off
宣言された構造のレイアウトをオフにします。#pragma ms_struct reset
デフォルトのレイアウトに戻ります。