5

C を探索するためにいくつかのサンプル プログラムを実行していますが、構造体のパディングが 2 のべき乗でしか実行できない理由を知りたいです。

#include <stdio.h>

#pragma pack(push, 3)

union aaaa
{

   struct bbb
   {
      int a;
      double b;
      char c;
   }xx;

   float f;
};

#pragma pack(pop)

int main()
{

printf("\n Size: %d", sizeof(union aaaa));

return 0;
}

コンパイル中

warning: alignment must be a small power of two, not 3 [-Wpragmas]
warning: #pragma pack (pop) encountered without matching #pragma pack (push) [-Wpragmas]

#pragma は効果がないようです。出力は 24 のみです。つまり、4 バイト アラインされます。

4

5 に答える 5

21

簡単に言えば、プロセッサ内の基本オブジェクトのサイズは小さい 2 の累乗 (1、2、4、8、16 バイトなど) であり、メモリは小さい 2 の累乗のサイズ (たとえば 8 バイト) のグループに編成されます。バイト)、そのため、これらのサイズでうまく機能するように構造体を揃える必要があります。

長い答えは、その理由が物理学と初等数学に基づいているということです。コンピュータは当然、値 0 と 1 のビットで動作します。これは、高電圧と低電圧、電荷の有無など、2 つの値の間で切り替わる物理的なものを簡単に設計できるためです。3 つの値を区別することは、値間の遷移についてより敏感でなければならないため、より困難です。そのため、コンピューター技術が数十年にわたって発展してきたため、3 進数などの代替手段の代わりにビット (2 進数) を使用してきました。

より大きな数を作成するには、複数のビットを組み合わせます。したがって、2 つのビットを組み合わせると、4 つの値を持つことができます。3 ビットは 8 つの値を持つことができます。古いコンピューターでは、ビットが一度に 6 つまたは 10 にグループ化されることがありました。しかし、8が一般的になり、現在では基本的に標準になっています。1 バイトに 8 ビットを使用することには、私が説明する他のいくつかのグループ化ほど強い物理的な理由はありませんが、それが世界のやり方です。

コンピュータのもう 1 つの機能はメモリです。これらのバイトを取得したら、プロセッサが簡単にアクセスできるデバイスに大量のバイトを格納して、プロセッサに大量のバイトをすばやく出し入れできるようにします。大量のバイトがある場合、プロセッサがどのバイトを読み書きしたいかをプロセッサがメモリに伝える方法が必要です。そのため、プロセッサにはバイトをアドレス指定する方法が必要です。

プロセッサは値にビットを使用するため、アドレス値にビットを使用します。そのため、メモリは、プロセッサが読み取るときにプロセッサに提供するバイト、またはプロセッサが書き込むときに格納するバイトを示すビットを受け入れるように構築されます。メモリ デバイスはこれらのビットで何をしますか? 簡単なことは、メモリへの経路の 1 つのスイッチを制御するために 1 ビットを使用することです。メモリは、バイトを格納する多くの小さな部品で構成されます。

1 バイトを格納できるメモリ デバイスを考えてみましょう。A と B など、隣接する 2 つのものを考えてみましょう。スイッチを使用して、A バイトをアクティブにするか、B バイトをアクティブにするかを選択できます。活動する。ここで、A、B、C、D の 4 つを考えてみましょう。1 つのスイッチで、AB グループを使用するか、CD グループを使用するかを選択できます。次に、別のスイッチで A または B (AB グループを使用する場合) または C または D (CD を使用する場合) グループを選択します。

このプロセスは続きます。メモリ アドレスの各ビットは、使用するストレージ ユニットのグループを選択します。1 ビットは 2 つのストレージ ユニットから選択し、2 は 4 から選択し、3 は 8 から選択し、4 は 16 から選択します。8 ビットは 256 のストレージ ユニットから選択し、24 ビットは 16,777,216 のストレージ ユニットから選択し、32 ビットは 4,294,967,296 のストレージ ユニットから選択します。

もう 1 つの複雑な問題があります。プロセッサとメモリ間の個々のバイトの移動は低速です。代わりに、最新のコンピューターはメモリを 8 バイトなどの大きな単位に編成します。メモリとプロセッサの間で一度に移動できるのは 8 バイトだけです。プロセッサがメモリに何らかのデータを提供するように要求すると、プロセッサはアドレスの上位ビットのみを送信します。下位 3 ビットは 8 バイト内の個々のバイトを選択し、メモリには送信されません。

これは、1 バイトを供給するためにメモリがすべてのスイッチングを実行するのに必要な時間で、プロセッサが 8 バイトを取得するため高速であり、個々を区別するために必要な膨大な数の余分なスイッチが必要ないため安価です。メモリ内のバイト。

ただし、これは、プロセッサがメモリから個々のバイトを取得する方法がないことを意味します。個々のバイトにアクセスする命令を実行する場合、プロセッサはメモリから 8 バイトを読み取り、それらのバイトをプロセッサ内でシフトして、必要な 1 バイトを取得する必要があります。同様に、2 バイトまたは 4 バイトを取得する場合、プロセッサは 8 バイトを読み取り、必要なバイトだけを抽出します。

このプロセスを簡素化するために、プロセッサの設計者は、データを特定の方法で整列させる必要があることを指定します。通常、2 バイト データ (16 ビット整数など) を 2 バイトの倍数に揃える必要があり、4 バイト データ (32 ビット整数や 32 ビット浮動小数点値など) を 4 の倍数に揃える必要があります。バイト、および 8 バイトの倍数に整列される 8 バイト データ。

この必要なアライメントには 2 つの効果があります。まず、4 バイトのデータは、メモリから読み取った 8 バイトのチャンクの 2 つの場所 (先頭または中間) からしか開始できないため、プロセッサの設計者は 2 つの場所から 4 バイトを抽出するためにワイヤを配置するだけで済みます。アラインメントが許可されている場合、開始位置になる可能性のある 8 つの個々のバイトから 4 バイトを抽出するために、余分なワイヤをすべて追加する必要はありません。(一部のプロセッサは、整列されていないデータのロードを完全に禁止し、一部のプロセッサはそれを許可しますが、より少ないワイヤを使用する遅い方法を使用してデータを抽出しますが、反復アルゴリズムを使用して複数のプロセッサ サイクルにわたってデータをシフトするため、整列されていないロードは低速です。)

2 番目の効果は、4 バイト データは 8 バイト チャンク内の 2 つの場所からしか開始できないため、そのチャンク内でも終了することです。8 バイトのチャンクの 6 番目のバイトから始まる 4 バイトのデータをロードしようとするとどうなるか考えてみてください。最初の 2 バイトはチャンクにありますが、次の 2 バイトはメモリ内の次のチャンクにあります。プロセッサは、メモリから 2 つのチャンクを読み取り、それぞれから異なるバイトを取得して、それらのバイトを結合する必要があります。これは、1 つのチャンクを読み取るよりもはるかに遅くなります。

したがって、メモリはビットの自然な結果である 2 の累乗で構成され、メモリ アクセスがより効率的になるため、プロセッサはアライメントを必要とします。アラインメントは当然 2 のべき乗であるため、アラインメントに使用される 2 のべき乗の倍数であると、構造体のサイズが適切に機能します。

于 2012-07-26T12:25:05.230 に答える
8

そうしないと意味がないからです。構造体にパディングを追加するのは、CPU がアラインされたデータに対してより高速に動作し (一部のアーキテクチャでは、アラインされていないデータに対してはまったく機能しないため)、さまざまなデータ型のアラインメント要件が常に 2 の小さなべき乗 (少なくとも、私が聞いたことのあるアーキテクチャで)。

それでも、何らかの奇妙な理由で任意のアラインメントが必要な場合はchar、適切な場所にダミー配列を追加してアラインメントを強制することを妨げるものは何もありません (これは、多かれ少なかれ、コンパイラがボンネットの下で行うことです)。

于 2012-07-26T10:21:40.133 に答える
0

GCC のドキュメント ( http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html ) によると、pack プラグマは「Microsoft Windows コンパイラとの互換性のために」使用されます。

アラインメントに関する MS ドキュメント ( http://msdn.microsoft.com/en-us/library/ms253949(v=vs.80).aspx ) を検索すると、MSVC コンパイラがデータに基づいて型のアラインメントを保証することがわかります。サイズ; 他の投稿で説明されているように、これは論理的に常に 2 のべき乗です。

問題がデータ構造の派手な配置が必要な場合 (よく考えられていないメモリ マップされた周辺機器にアクセスするため) 、必要なパディングを追加するフィールドを追加して、構造の手動パッキングを使用することをお勧めします。

于 2012-07-26T13:44:23.660 に答える