私は32ビットマシンで作業しているので、メモリアライメントは4バイトにする必要があると思います。構造体があるとします:
_typedef struct {
unsigned short v1;
unsigned short v2;
unsigned short v3;
} myStruct;
_
実際のサイズは6バイトで、整列サイズは8であると仮定しますが、sizeof(myStruct)
は6を返します。
しかし、私が書いた場合:
_typedef struct {
unsigned short v1;
unsigned short v2;
unsigned short v3;
int i;
} myStruct;
_
実際のサイズは10バイト、alignedは12、そして今回はsizeof(myStruct) == 12
です。
誰かがその違いを説明できますか?
exactlyが同じで、a differenceは、宣言される順序が異なるため、各構造体のサイズは異なる場合があります(多くの場合、異なります)。
たとえば、これを参照してください、
#include <iostream>
using namespace std;
struct A
{
char c;
char d;
int i;
};
struct B
{
char c;
int i; //note the order is different!
char d;
};
int main() {
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
}
gcc-4.3.4
でコンパイルすると、次の出力が得られます。
8
12
つまり、両方の構造体のメンバーが同じであっても、サイズは異なります!
Ideoneのコード: http://ideone.com/HGGVl
要するに、標準ではパディングの実行方法については説明されていないため、コンパイラーは自由に決定を下すことができ、ユーザーはcannotすべてを仮定しますコンパイラーも同じ決定を下します。
デフォルトでは、値はサイズに応じて整列されます。したがって、short
のような2バイト値は2バイト境界に位置合わせされ、int
のような4バイト値は4バイト境界に位置合わせされます
この例では、i
の前に2バイトのパディングを追加して、i
が4バイト境界に収まるようにします。
(構造全体は、少なくとも構造内の最大値と同じ大きさの境界に位置合わせされるため、構造は4バイト境界に位置合わせされます。)
実際のルールはプラットフォームによって異なります- データ構造のアライメント のWikipediaページに詳細があります。
コンパイラでは通常、(たとえば)#pragma pack
ディレクティブ。
想定:
sizeof(unsigned short) == 2
sizeof(int) == 4
次に、私は個人的に次のものを使用します(コンパイラは異なる場合があります)。
unsigned shorts are aligned to 2 byte boundaries
int will be aligned to 4 byte boundaries.
typedef struct
{
unsigned short v1; // 0 bytes offset
unsigned short v2; // 2 bytes offset
unsigned short v3; // 4 bytes offset
} myStruct; // End 6 bytes.
// No part is required to align tighter than 2 bytes.
// So whole structure can be 2 byte aligned.
typedef struct
{
unsigned short v1; // 0 bytes offset
unsigned short v2; // 2 bytes offset
unsigned short v3; // 4 bytes offset
/// Padding // 6-7 padding (so i is 4 byte aligned
int i; // 8 bytes offset
} myStruct; // End 12 bytes
// Whole structure needs to be 4 byte aligned.
// So that i is correctly aligned.
まず、パディングの詳細はコンパイラーに任されていますが、OSはアライメント要件に関していくつかの規則を課しています。この回答は、OSが異なる場合がありますが、gccを使用していることを前提としています
特定の構造体とその要素が占めるスペースを決定するには、次のルールに従います。
最初に、構造体が常にallデータ型に適切に位置合わせされたアドレスで始まると仮定します。
次に、構造体のすべてのエントリに対して:
sizeof(element)
で指定された要素の生のサイズです。char[20]
配列のアライメント要件がプレーンchar
の要件と同じであることを意味します。最後に、構造体全体のアライメント要件は、各要素のアライメント要件の最大値です。
gccは指定された要素の後にパディングを挿入して、次の要素(または最後の要素について話している場合は構造体)が正しく整列されるようにします。 neverは、メモリを節約する場合でも、構造体の要素の順序を並べ替えます。
アライメント要件自体も少し変わっています。
0x0
、0x4
、0x8
または0xC
で終わるアドレス)を持つ必要があります。これは、4バイトより大きい型(double
やlong double
など)にも適用されることに注意してください。double
は、0x0
または0x8
で終わるアドレスにのみ配置できます。これに対する唯一の例外は、long double
であり、実際には12バイトの長さであるにもかかわらず、4バイトにアライメントされています。long double
は例外であり、16バイトに揃える必要があります。各データ型は、独自のサイズのメモリ境界に揃える必要があります。したがって、short
は2バイト境界に位置合わせする必要があり、int
は4バイト境界に位置合わせする必要があります。同様に、long long
は8バイト境界にある必要があります。
2番目のsizeof(myStruct)
が12
である理由は、v3
とi
の間に挿入され、i
を32ビットに揃えるパディングです。境界。 2バイトあります。
Wikipedia は、パディングと整列を合理的に明確に説明しています。
各varのサイズに基づいて境界に配置されているように聞こえるので、アドレスがアクセスされるサイズの倍数になります(したがって、shortsが2に整列され、intが4に整列されます)。 int、sizeof(mystruct)
は10である必要があります。もちろん、これはすべて、使用されているコンパイラーと、使用されている設定によって決まります。
標準では、完全な型の構造体のレイアウトについてはあまり言及されていません。コンパイラ次第です。アクセスするために境界で開始するにはintが必要であると判断しましたが、ショートのためにサブ境界のメモリアドレス指定を行う必要があるため、それらをパディングする必要はありません