2012-08-06 6 views
8

this questionユニオンのアライメントは、それが個々のメンバーの最大のアライメントよりも小さくないと信じ始める可能性があります。しかし、gcc/g ++のlong longタイプに問題があります。完全な例はhere見つけましたが、ここで私の質問に関連する部分であり、することができます。これは、次のような出力になりなぜ長いlong unionメンバのアライメントがcontains union/structよりも大きいのですか?これは正しいです?

union ull { 
    long long m; 
}; 

struct sll { 
    long long m; 
}; 


int main() { 
#define pr(v) cout << #v ": " << (v) << endl 
    pr(sizeof(long long)); 
    pr(__alignof__(long long)); 
    pr(sizeof(ull)); 
    pr(__alignof__(ull)); 
    pr(sizeof(sll)); 
    pr(__alignof__(sll)); 
}; 

sizeof(long long): 8 
__alignof__(long long): 8 
sizeof(ull): 8 
__alignof__(ull): 4 
sizeof(sll): 8 
__alignof__(sll): 4 

よりもメンバー大きな労働組合の整列があるのはなぜ含有組合の?

は[UPDATE]

alignofキースの答えによると、ここで間違っています。しかし、私は次のことを試してみると、それはのalignofが真実を教えてくれるようです。参照:

union ull { 
    long long m; 
}; 
long long a; 
char b; 
long long c; 
char d; 
ull e; 
int main() { 
#define pr(v) cout << #v ": " << (v) << endl 
    pr(size_t((void*)&b)); 
    pr(size_t((void*)&c)); 
    pr(size_t((void*)&d)); 
    pr(size_t((void*)&e)); 
    pr(size_t((void*)&c) - size_t((void*)&b)); 
    pr(size_t((void*)&e) - size_t((void*)&d)); 
}; 

出力:

size_t((void*)&b): 134523840 
size_t((void*)&c): 134523848 
size_t((void*)&d): 134523856 
size_t((void*)&e): 134523860 
size_t((void*)&c) - size_t((void*)&b): 8 
size_t((void*)&e) - size_t((void*)&d): 4 

したがって、long longのアラインメントは8とlong longを含む組合のアラインメントは、グローバルデータ4です。ローカルスコープについては、コンパイラがローカルデータを自由に並べ替えることができるように見えるので、これをテストすることはできません。このトリックは機能しません。これについてコメントできますか?

[/ UPDATE]

+1

gcc 4.7.0では '-m32'と同じことが見られますが、' -m64'では(すべて '8'sで)*ではありません。 – BoBTFish

+1

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023 _Alignof(C11)の対応するgccバグへのリンク。 –

答えて

7

__alignof__(GCC拡張である)必ずしもタイプの必要アラインメントを報告しません。

x86プロセッサでは、実際にはどのタイプでも1バイト以上の整列は必要ありません。オブジェクトがワードで整列されていても、バイト整列で十分であれば、4バイトまたは8バイトのオブジェクトへのアクセスはより効率的になります。

gcc documentationを引用:

一部のマシンでは、実際にアライメントを必要としません。奇数アドレスでもデータ型に参照 を許可します。これらのマシンの場合、 __alignof__は、GCCが データ型を指定する最小のアライメントを報告します。通常、ターゲットABIが指定します。

しかし、それでも実際には質問には答えません。その緩い定義であっても、がlong longのより厳密なアラインメントを示す理由は、long longを含む構造体またはユニオンの場合よりも、私は考えることができません。

タイプのアライメントを決定するためのより多くのポータブル方法はこれです:

#define ALIGNOF(type) ((int)(offsetof(struct {char c; type t;}, t))) 

これはchartからなる構造体でタイプtのメンバのオフセットが得られます。このマクロを使用して、このプログラム:

#include <iostream> 
#include <cstddef> 

union ull { 
    long long m; 
}; 

struct sll { 
    long long m; 
}; 

#define ALIGNOF(type) ((int)(offsetof(struct {char c; type t;}, t))) 

int main() { 
#define pr(v) std::cout << #v ": " << (v) << std::endl 
    pr(sizeof(long long)); 
    pr(__alignof__(long long)); 
    pr(ALIGNOF(long long)); 
    pr(sizeof(ull)); 
    pr(__alignof__(ull)); 
    pr(ALIGNOF(ull)); 
    pr(sizeof(sll)); 
    pr(__alignof__(sll)); 
    pr(ALIGNOF(sll)); 
}; 

は私のシステム(GCC-4.7は、Ubuntu 12.04、x86の)上に出力を生成する:

sizeof(long long): 8 
__alignof__(long long): 8 
ALIGNOF(long long): 4 
sizeof(ull): 8 
__alignof__(ull): 4 
ALIGNOF(ull): 4 
sizeof(sll): 8 
__alignof__(sll): 4 
ALIGNOF(sll): 4 

ALIGNOF()マクロで示す結果が一致している:long longを有します4バイト境界整列、およびlong longを含む構造体または共用体は4バイト境界整列を持ちます。

これはgccの実装が__alignof__のバグか、少なくとも矛盾していると思われます。しかし、定義の漠然としていることは、それが実際にバグであることを確かめるのを困難にします。 It doesn't seem to have been reported

更新:

私は銃をジャンプすることができるが、私はちょうどbug reportを提出しました。

この「」は、「INVALID」として閉じられていますが、構造自体のアライメントを参照するものではありません。

アップデート2:

私のバグレポートは、1以前の重複として閉じられています。私は説明を求めています。

+0

この 'ALIGNOF()'ヒントに感謝します。 – PiotrNycz

+0

ただし、NonPODではoffsetofがNonPODで機能しないため、このマクロはNonPODタイプでは機能しません(http://stackoverflow.com/questions/1129894/why-cant-you-use-offsetof-on-nod-pod-strucutures- in-c)。あなたはNonPODタイプのために偶然知っていますか? – PiotrNycz

+0

あなたは私の更新についてコメントすることができます。 '__alignof __(long long)== 8'が正しいと思われます。あなたの 'ALIGNOF'でテストされているのは、' struct long'の 'struct long'を整列させるだけです。これは私の' struct sll {long long m; } '。おそらく、あなたのバグレポートのためのこのヘルプ。 – PiotrNycz

関連する問題