2009-05-08 14 views
84

Aşağıdaki kodu var:Yığın değişkenleri GCC __attribute __ ((align (x))) ile hizalanmış mı?

#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]); 
} 

Ve şu çıktıyı var:

a[0] adresi 0x1000 bir katı değil neden
0x7fffbfcd2da0 0x7fffbfcd2da4 0x7fffbfcd2da8 0x7fffbfcd2dac 

?

Tam olarak __attribute__((aligned(x))) ne yapar? this açıklamasını yanlış anlamış mıyım?

Gcc 4.1.2 kullanıyorum.

cevap

94

Sorun, dizininizin yığının üstünde olduğuna inanıyorum. İşlev başladığında yığın gösterici herhangi bir şey olabileceğinden, diziyi ihtiyaç duyduğunuzdan ve ayarlamadan çok daha fazlasını ayırmadan hizalamanın bir yolu yoktur. Diziyi işlevin dışına taşırsanız ve genel bir değişkene taşırsanız, çalışmalıdır. Yapabileceğiniz diğer şey, onu yerel bir değişken olarak tutmaktır (ki bu çok iyi bir şeydir), ancak static'u yapın. Bu, yığında saklanmasını engeller. Dizinin yalnızca bir kopyası olacağından, bu yolların her ikisinin de thread-safe veya recursion-safe olmadığından emin olun. Bu kod ile

:

#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]); 
} 

Ben bu olsun:

0x804c000 0x804c004 0x804c008 0x804c00c 

hangi beklenen budur. Orijinal kodunuzla, yaptığınız gibi rastgele değerler alıyorum.

+11

+1 doğru yanıt. Alternatif bir çözüm, yerel diziyi statik yapmaktır. Yığındaki hizalama her zaman bir problemdir ve kaçınmaktan kaçınmak en iyisidir. –

+0

Oh evet, onu statik yapmayı düşünmedim. Bu isim çarpışmasını önlediği için iyi bir fikir. Cevabımı düzenleyeceğim. – Zifre

+2

Statik hale getirilmesinin, aynı zamanda reentran olmayan ve iplik olmayan güvenli olmasını da sağladığını unutmayın. – ArchaeaSoftware

9

Hizalama her tür için etkili değildir. Okumak edeceğiz, o zaman

#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]); 
} 

Ve: Sen eylem özelliklerini görmek için bir yapıyı kullanmayı düşünmelisiniz Beklediğiniz ne

0x603000 0x604000 0x605000 0x606000 

.

Düzenleme: @yzap ve aşağıdaki @Caleb Vaka yorum tarafından itilen ilk sorun GCC sürümü sadece kaynaklanmaktadır. Ben istek sahibinin kaynak koduyla GCC 4.4.1 vs GCC 3.4.6 kontrol ettim:

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

O eski GCC sürümleri (bir yere 4.4.1 öncesi) hizalama patolojileri gösteren şimdi ortada.

Not 1: Önerilen kodum, "dizinin her alanını hizalama" olarak anladığım soruyu yanıtlamıyor.

Not 2: Statik olmayan a [] 'ı ana()' ye getirmek ve GCC 3.4.6 ile derlemek, struct dizisinin hizalama yönergesini kırar ancak struct'ler arasında 0x1000 mesafesini korur ... hala kötü! (bkz. geçici çözümler için yanıtla)

+1

Zifre tarafından yanıtlandığı gibi, bu tür değil, ancak sürümünüzde statik yaptığınız gerçektir. – ysap

+0

@ysap, çalışmasını sağlayan hem GCC sürüm hem de global tanımdı. Yorumunuz için teşekkürler! Düzeltmek için cevabı düzenledim. :) – levif

13

Son GCC (4.5.2-8ubuntu4 ile test edilmiştir) dizinin düzgün hizalanmasıyla beklendiği gibi çalıştığı görünmektedir.

#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]); 
} 

alıyorum:

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

Diziler yığına ayrıldıkları düşünüldüğünde bu biraz şaşırtıcı, yani yığının deliklerle dolu olduğu anlamına mı geliyor? – ysap

+0

Ya da onun yığını 16 bayt hizalanmış. – user7116

38

yığın değişkenleri ile çalışmaz hizalanmış niteliği neden gcc bir hata oluştu. Aşağıda bağlantılı yama ile sabitlenmiş gibi görünüyor. Aşağıdaki bağlantı da sorun için biraz tartışma içeriyor.

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

İki farklı gcc'nin sürümleri ile yukarıda kodunuzu denedim: RedHat 5.7 kutusundan 4.1.2 ve 0x1000 üzerinde hizalanmış hiçbir şekilde wre yerli dizilerin (sorununuza benzer başarısız bayt sınırları. Daha sonra kodunuzu RedHat 6.3'te gcc 4.4.6 ile denedim ve kusursuz çalıştı (yerel diziler hizalandı). Eğer sonraki sürümlerinde giderilmiştir gibi görünen gcc bir hata bulundu gibi görünüyor, neyse

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

: Mit TV millet (gcc yama yukarıda düzeltmek için görünüyordu) benzer bir sorun vardı.

+3

Bağlantılı hataya göre gcc 4.6, tüm mimariler için tam olarak bu sorun ile ilk sürüm oldu. – textshell

İlgili konular