web-dev-qa-db-ja.com

一部のマシンでlong intが12バイトかかるのはなぜですか?

私のマシンでこのコードをコンパイルした後、奇妙なことに気づきました:

#include <stdio.h>

int main()
{
    printf("Hello, World!\n");

    int a,b,c,d;

    int e,f,g;

    long int h;

    printf("The addresses are:\n %0x \n %0x \n %0x \n %0x \n %0x \n %0x \n %0x \n %0x",
        &a,&b,&c,&d,&e,&f,&g,&h);

    return 0;
}

結果は次のとおりです。すべてのintアドレスの間に4バイトの違いがあることに注意してください。ただし、最後のintとlong intの間には12バイトの違いがあります。

 Hello, World!
 The addresses are:

 da54dcac 
 da54dca8 
 da54dca4 
 da54dca0 
 da54dc9c 
 da54dc98 
 da54dc94 
 da54dc88
26
yoyo_fun

12バイトではなく、8バイトしかかかりませんでした。ただし、このプラットフォームでの8バイト長のintのデフォルトの alignment は8バイトです。そのため、コンパイラはlong intを8で割り切れるアドレスに移動する必要がありました。「明白な」アドレスda54dc8cは8で割り切れないため、12バイトのギャップがあります。

これをテストできるはずです。 longの前に別のintを追加して、8個ある場合、long intは移動せずに整列されることに気付くはずです。これで、前のアドレスからわずか8バイトになります。

おそらく指摘する価値があります。このテストは機能するはずですが、このように編成された変数に依存するべきではありません。 Cコンパイラーは、変数の並べ替えを含め、プログラムをすばやく実行するために、あらゆる種類のファンキーなことを実行できます(いくつかの注意点があります)。

81
Alex

これは、メモリ内で変数が正しく整列されるように、コンパイラーが変数間に追加のパディングを生成しているためです。

最近のほとんどのプロセッサでは、値にそのサイズの倍数のアドレスがある場合、アクセスする方が効率的です。最初の利用可能な場所にhを配置した場合、そのアドレスは0xda54dc8cであり、8の倍数ではないため、使用する効率が低下します。コンパイラーはこれを認識しており、最後の2つの変数の間に未使用のスペースを少し追加して、それを確実に実現します。

9
Jules

これらのローカル変数のいずれかのアドレスを相互に関連付けるための言語の要件がないため、テストは必ずしもユーザーの意図をテストしているわけではありません。

ストレージの割り当てについて何かを推測できるようにするには、これらを構造体のフィールドとして配置する必要があります。

ローカル変数は、特定の方法で隣同士にストレージを共有する必要はありません。コンパイラは、スタック内の任意の場所に一時変数を挿入する場合があります。たとえば、これらのローカル変数の2つの間にある可能性があります。

対照的に、構造体に一時変数を挿入することはできません。そのため、構造体フィールドのアドレスを出力した場合、同じメモリ(構造体)から割り当てられたアイテムを比較することになります。

2
Erik Eidt