5

これはメモリアラインメントに関するものです。以下のコードでは、構造内の b のオフセットが 8 (32 ビット マシン) であると予想しました。ここを参照してください。これにより、b常にキャッシュ ライン内で発生するようになります。しかし、そうではありません。bのグローバル オブジェクトのメンバーはstruct test1整列しているようです。偶然なのか、コンパイラが意図的にこれを行っているのかはわかりません。

コンパイラが の後に 4 バイトをパディングしない理由を理解したかったのaです。

struct test1
{
int a;
double b;
}t1;

int main()
{
struct test1 *p = malloc(sizeof(struct test1));
printf("sizes int %d, float %d, double %d, long double %d\n", sizeof(int), sizeof(float), sizeof(double), sizeof(long double));
printf("offset of b %d\n",(int)&(t1.b)-(int)&(t1));

printf("\naddress of b (on heap) = %p, addr of b (on data seg) = %p\n",&(p->b), &(t1.b));

return 0;
}

出力は...

sizes int 4, float 4, double 8, long double 12
offset of b 4

address of b (on heap) = 0x804a07c, addr of b (on data seg) = 0x80497e0

ubuntu 10.04で標準のgccコンパイラを使用しています

4

3 に答える 3

5

System V ABI for i386の 28 ページによると、double4 バイトのアラインメントしか取得できませんが、コンパイラは 8 バイトのオプションも提供することをお勧めします。これは Linux 上の GCC によって実装されているようで、オプションは-malign-double.

もう 1 つの方法は、-m64x86-64 オブジェクト コードを取得するために を使用することです。これは、Mac OS X を含む一部のシステムでは既にデフォルトになっています。

于 2013-02-15T14:08:18.857 に答える
4

構造内の b のオフセットは 8 (32 ビット マシン) であると予想しました。こちらをご覧ください

あなたの参考文献は、8 アラインのダブルが有利な理由を説明しています。これは、ダブルスが常に 8 アラインされることを保証するものではありません。ソースが常に 8 アラインであると述べていて、そうでない実装を観察した場合、そのソースは間違っています。

GCC の man ページから:

"double" 変数を 2 ワード境界に揃えると、Pentium でより多くのメモリを犠牲にして多少高速に実行されるコードが生成されます。

したがって、GCC が 4 アラインメントについて述べている理由は、メモリを節約するためです。とを使用-malign-doubleしてそれ-mno-align-doubleを制御できますが、競合するオプションでコンパイルされたコード間で構造体を共有すると、バイナリの非互換性が生じるリスクがあります。特定のオブジェクト/構造体メンバーについては、GCC 独自の__attribute__((aligned)), _Alignas(C11 の場合) またはalignas(C++11 の場合) を使用できます。これらはすべて整数定数を使用して、必要なアラインメントを指定できます。

于 2013-02-15T12:58:17.260 に答える
0

ANSI Cでは、位置合わせについての保証はまったくありません。

アラインメントは、ヒープ上で宣言されたものよりも自動変数で発生します。POSIX OSを使用している場合は、memalign(3)を使用して、整列されていることが確実なメモリを受け取ります。Mallocは、任意のオフセットでメモリを返す可能性があります。__attribute__ ((__packed__))独自のアライメントを設定するようなコンパイラ指令を使用できます。

于 2013-02-15T11:47:35.577 に答える