起こっているのは構造パディングです。
これは、要素がアラインされたメモリ アドレスに存在することを保証するために、コンパイラによって行われます。
x86/x86_64 の「アライメント」について詳しくは、こちらをご覧ください。
では、なぜそれらはアラインされたアドレスにある必要があるのでしょうか? (例として 4 バイトの WORD を使用):マシンはメモリからのデータに「ワード」でアクセスします。4 バイトの WORD の場合、これは、アドレスから 1 バイトを読み取るには、b11001110
4 バイトを読み取る必要があることを意味します (アドレスの最後の 2 ビットは基本的に、読み取り中に無視されます)。次に、必要なバイトを 1 回選択します。 WORDはCPUにあります:
| b11001100 | b11001101 | b11001110 | b11001111 | <- all four loaded at once
\ /
only one used
より大きなデータ型の読み取りを開始すると、「整列されていない」データムの読み取りは、整列されたデータムの読み取りよりもコストがかかる可能性があります。
1 バイトだけではなく、アドレスから 4 バイト (1 WORD) をb01110
読み取る場合は、2 WORDS を読み取る必要があります。
first load second load
/ \/ \
|01100|01101|01110|01111|10000|10001|10010|10011|
\ /
unaligned data read
コンパイラは、このような読み取りを避けるために構造を「パディング」します。コストがかかるからです。Woodrow Douglass が回答で示唆しているように、コンパイラに「パッド」ではなく「パック」を強制できます。
もう 1 つ: アラインされていないロードが不可能なアーキテクチャもあります。このようなマシンでは、通常、オペレーティング システムは非整列ロード中に発生した例外をキャッチし、何らかの方法で (たとえば、複数の整列ロードを実行することによって) ロードをシミュレートします。