この標準は、POD構造体(つまり、最も制限の厳しいクラスの構造体)でさえ、メンバー間にパディングを含めることができるというかなり具体的なものです。(「したがって、POD-structオブジェクト内に名前のないパディングがある可能性がありますが、適切な配置を実現するために必要な場合は、最初はそうではありません。」-非規範的なメモですが、意図は非常に明確です)。
たとえば、標準レイアウト構造体(C ++ 11、§1.8/ 4)の要件を対比します。
自明にコピー可能なタイプまたは標準レイアウトタイプ(3.9)のオブジェクトは、連続したバイトのストレージを占有するものとします。」
...アレイ用のもの(§8.3.4/ 1):
配列型のオブジェクトには、T型のN個のサブオブジェクトの連続して割り当てられた空でないセットが含まれています。
配列では、要素自体を連続して割り当てる必要がありますが、構造体では、ストレージのみを連続して割り当てる必要があります。
「連続ストレージ」要件をより意味のあるものにする可能性のある3番目の可能性は、簡単にコピーできない、または標準のレイアウトではない構造体/クラスを検討することです。この場合、ストレージがまったく隣接していない可能性があります。たとえば、実装では、すべてのプライベート変数を保持するための1つのメモリ領域と、すべてのパブリック変数を保持するための完全に別個のメモリ領域を確保する場合があります。これをもう少し具体的にするために、次のような2つの定義を検討してください。
class A {
int a;
public:
int b;
} a;
class B {
int x;
public:
int y;
} b;
これらの定義を使用すると、メモリは次のようにレイアウトされます。
a.a;
b.x;
// ... somewhere else in memory entirely:
a.b;
b.y;
この場合、要素もストレージも隣接している必要はないため、完全に別個の構造体/クラスの部分をインターリーブすることは許可されます。
とはいえ、最初の要素は全体として構造体と同じアドレスにある必要があります(9.2 / 17): "reinterpret_castを使用して適切に変換されたPOD-structオブジェクトへのポインターは、最初のメンバー(またはそのメンバーの場合)を指しますはビットフィールドであり、それが存在するユニットになります)、またはその逆です。」
あなたの場合、POD-structがあるので、(§9.2/ 17): "reinterpret_castを使用して適切に変換されたPOD-structオブジェクトへのポインターは、その最初のメンバーを指します(または、そのメンバーがビットフィールドの場合)。 、次にそれが存在するユニットに)、およびその逆。」最初のメンバーは整列され、残りのメンバーはすべて同じタイプであるため、他のメンバー間でパディングが本当に必要になることは不可能です(つまり、ビットフィールドを除いて、構造体に配置できるタイプは、配列。要素の連続的な割り当てが必要です)。単語指向のマシン(初期のDEC Alphaなど)で単語よりも小さい要素がある場合は、パディングによってアクセスがいくらか簡単になる可能性があります。たとえば、初期のDEC Alpha(ハードウェアレベル)は、一度に完全に(64ビット)ワードを読み書きすることしかできませんでした。char
そのため、4つの要素の構造体のようなものを考えてみましょう。
struct foo {
char a, b, c, d;
};
これらをメモリに配置して連続さfoo::b
せる必要がある場合、(たとえば)にアクセスするには、CPUがワードをロードし、それを8ビット右にシフトしてから、マスクしてそのバイトをゼロ拡張して全体を埋める必要があります。登録。
保存はさらに悪化します。CPUは単語全体の現在の値をロードし、その適切な文字サイズの部分の現在の内容をマスクして、新しい値を正しい場所にシフトするか、単語に挿入する必要があります。 、そして最後に結果を保存します。
対照的に、要素間にパディングを使用すると、各要素はシフトやマスキングなどのない単純なロード/ストアになります。
少なくとも、メモリが機能する場合、Alpha用のDECの通常のコンパイラでは、int
32ビットであり、long
64ビットでした(以前はlong long
)。そのため、4int
の構造体を使用すると、要素間にさらに32ビットのパディングが表示されると予想できます(最後の要素の後にさらに32ビットも表示されます)。
あなたがPOD構造体を持っていることを考えると、あなたはまだいくつかの可能性を持っています。私がおそらく好むoffsetof
のは、構造体のメンバーのオフセットを取得し、それらの配列を作成し、それらのオフセットを介してメンバーにアクセスするために使用することです。以前のいくつかの回答でこれを行う方法を示しました。