2009-05-08 11 views
84

iは、次のコードを持っている:スタック変数はGCCの__attribute __((aligned(x)))で整列されていますか?

#include <stdio.h> 

int 
main(void) 
{ 
     float a[4] __attribute__((aligned(0x1000))) = {1.0, 2.0, 3.0, 4.0}; 
     printf("%p %p %p %p\n", &a[0], &a[1], &a[2], &a[3]); 
} 

を、私は次の出力があります。a[0]のアドレスは0x1000の倍数でないのはなぜ

0x7fffbfcd2da0 0x7fffbfcd2da4 0x7fffbfcd2da8 0x7fffbfcd2dac 

を?

正確には__attribute__((aligned(x)))とは何ですか?私は誤解したthisの説明は?

私はgcc 4.1.2を使用しています。

答えて

94

私は問題があなたの配列がスタック上にあると信じています。関数が起動するときにスタックポインタが何かになる可能性があるため、必要以上に多くの割り当てを行わずに配列を整列させて調整する方法はありません。配列を関数からグローバル変数に移動すると、配列が機能するはずです。あなたが行うことができるもう一つのことはローカル変数(これは非常に良いことです)として保つことですが、それをstaticにしてください。これにより、スタックに格納されなくなります。配列のコピーは1つしかないので、これらの方法のどちらもスレッドセーフでも再帰的にも安全ではないことに注意してください。このコードでは

#include <stdio.h> 

float a[4] __attribute__((aligned(0x1000))) = {1.0, 2.0, 3.0, 4.0}; 

int 
main(void) 
{ 
     printf("%p %p %p %p\n", &a[0], &a[1], &a[2], &a[3]); 
} 

私はこれを取得:

0x804c000 0x804c004 0x804c008 0x804c00c 

期待されているものです。元のコードでは、私はちょうどあなたのようにランダムな値を取得します。

+11

+1正解。別の解決策は、ローカル配列を静的にすることです。スタック上のアライメントは常に問題であり、回避する習慣に入るのが最善です。 –

+0

ああ、私はそれを静的にすることを考えなかった。それは名前の衝突を防ぐので、良いアイデアです。私は私の答えを編集します。 – Zifre

+2

これを静的にすると、スレッドはリエントラントでなくなり、スレッドセーフではありません。 – ArchaeaSoftware

9

アライメントはすべてのタイプで有効ではありません。

#include <stdio.h> 

struct my_float { 
     float number; 
} __attribute__((aligned(0x1000))); 

struct my_float a[4] = { {1.0}, {2.0}, {3.0}, {4.0} }; 

int 
main(void) 
{ 
     printf("%p %p %p %p\n", &a[0], &a[1], &a[2], &a[3]); 
} 

そして、あなたが読んであげる::あなたは、アクションの属性を参照するための構造を使用することを検討すべきである

0x603000 0x604000 0x605000 0x606000 

あなたが期待していたものですどの。

編集: @yzapと、次の@Calebケースコメントに押され、最初の問題は、GCCのバージョンのみによるものです。私は、要求側のソースコードをGCC 4.4.1対GCC 3.4.6で確認しました:

$ ./test_orig-3.4.6 
0x7fffe217d200 0x7fffe217d204 0x7fffe217d208 0x7fffe217d20c 
$ ./test_orig-4.4.1 
0x7fff81db9000 0x7fff81db9004 0x7fff81db9008 0x7fff81db900c 

それは古いGCCのバージョン(4.4.1以前にどこかで)アライメント病態を示すことになりまし明らかです。

注1:私の提案したコードは、「配列の各フィールドを整列させる」と私が理解した質問には答えません。

注2:main()内で非静的な[]を持ち、GCC 3.4.6でコンパイルすると構造体の配列のアラインメント指示が壊れますが、構造体間の距離は0x1000に留まります...まだ悪いです! (回避策については、@zifreの回答を参照してください)

+1

zifreが答えたように、それは型ではありませんが、あなたのバージョンで静的にしたという事実です。 – ysap

+0

@ysap、これはGCC版とグローバルな定義の両方で動作していました。コメントありがとう!私はそれを修正する答えを編集しました。 :) – levif

13

最近のGCC(4.5.2-8ubuntu4でテスト済み)は、配列が正しく整列された状態で期待どおりに動作するようです。

#include <stdio.h> 

int main(void) 
{ 
    float a[4] = { 1.0, 2.0, 3.0, 4.0 }; 
    float b[4] __attribute__((aligned(0x1000))) = { 1.0, 2.0, 3.0, 4.0 }; 
    float c[4] __attribute__((aligned(0x10000))) = { 1.0, 2.0, 3.0, 4.0 }; 

    printf("%p %p %p %p\n", &a[0], &a[1], &a[2], &a[3]); 
    printf("%p %p %p %p\n", &b[0], &b[1], &b[2], &b[3]); 
    printf("%p %p %p %p\n", &c[0], &c[1], &c[2], &c[3]); 
} 

は私が取得:

0x7ffffffefff0 0x7ffffffefff4 0x7ffffffefff8 0x7ffffffefffc 
0x7ffffffef000 0x7ffffffef004 0x7ffffffef008 0x7ffffffef00c 
0x7ffffffe0000 0x7ffffffe0004 0x7ffffffe0008 0x7ffffffe000c 
+0

配列がスタックに割り当てられていることを考えると、これはちょっと驚くべきことです - スタックには現在ホールがいっぱいですか? – ysap

+0

スタックは16バイトに整列されています。 – user7116

38

スタック変数では動作しないように整列属性を引き起こしたgccのバグがありました。 下記のリンク先のパッチで修正されているようです。下のリンクには、問題の議論もかなり含まれています。

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16660

私は、GCCの2つの異なるバージョンを持つ上に、あなたのコードを試してみました:決してローカル配列のWREが0x1000の上に整列(RedHatの5.7 ボックスから4.1.2、およびそれがあなたの問題と同様に失敗しました。バイト境界)。私は RedHat 6.3上のgcc 4.4.6でコードを試してみましたが、それは完璧に動作しました(ローカル配列が整列していました)。あなたはそれ以降のバージョンで修正されているように見えるのgccのバグを見つけたように見える、とにかく

http://code.mythtv.org/trac/ticket/6535

:神話テレビの人々は、(gccのパッチは、上記の修正に見えたということ)、同様の問題がありました。

+3

リンクされたバグgccによると、この問題がすべてのアーキテクチャで完全に修正された最初のリリースは4.6でした。 – textshell

関連する問題