Yığın değişkenleri GCC __özniteliği __ ((hizalı (x))) ile hizalı mı?


88

Takip koduna sahibim:

Ve şu çıktıya sahibim:

Adresi neden a[0]birden fazla değil 0x1000?

Tam olarak ne __attribute__((aligned(x)))yapar? Bu açıklamayı yanlış mı anladım ?

Gcc 4.1.2 kullanıyorum.

Yanıtlar:


98

Sorunun, dizinizin yığında olması ve derleyicinizin aşırı hizalanmış yığın değişkenlerini destekleyemeyecek kadar eski olması olduğuna inanıyorum. GCC 4.6 ve sonrası bu hatayı düzeltti .

C11 / C ++ 11 alignas(64) float a[4];Herhangi bir 2 hizalamanın gücü için çalışır. Sizin kullandığınız
GNU C __attribute__((aligned(x)))de öyle.

(In C11, #include <stdalign.h>için #define alignas _Alignas: cppref ).


Ancak 4k sayfa sınırına göre çok büyük bir hizalama durumunda, bunu yığında istemeyebilirsiniz.

Yığın işaretçisi, işlev başladığında herhangi bir şey olabileceğinden, ihtiyacınız olandan çok daha fazlasını ayırmadan ve onu ayarlamadan diziyi hizalamanın bir yolu yoktur. (Derleyiciler, and rsp, -4096tahsis edilen 0 ila 4088 bayttan hiçbirini kullanmayacak veya eşdeğeri kullanmayacak; bu alanın yeterince büyük olup olmadığına göre dallanma mümkün olabilirdi, ancak yapılmaz çünkü büyük hizalamalar dizinin veya diğer yerellerin boyutundan çok daha büyüktür. normal durum değildir.)

Diziyi işlevin dışına ve global bir değişkene taşırsanız, çalışması gerekir. Yapabileceğiniz diğer şey, onu yerel bir değişken olarak tutmaktır (ki bu çok iyi bir şeydir), ama yapın static. Bu, yığında depolanmasını önleyecektir. Dizinin yalnızca bir kopyası olacağından, bu iki yolun da iş parçacığı veya özyineleme güvenli olmadığına dikkat edin.

Bu kodla:

Bunu anlıyorum:

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


11
+1 doğru cevap. Alternatif bir çözüm, yerel diziyi statik yapmaktır. Yığın üzerinde uyum her zaman bir sorundur ve bundan kaçınma alışkanlığı edinmek en iyisidir.
Dan Olson

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

3
Statik hale getirmenin, aynı zamanda evresel olmayan ve iş parçacığı güvenli olmayan hale getirdiğini unutmayın.
ArchaeaSoftware

3
Ayrıca gcc 4.6+ bunu yığın üzerinde bile doğru şekilde halleder.
textshell

1
Bu cevap önceden doğruydu, ama şimdi değil. gcc, 4.6 kadar eski, belki daha eski, yığın işaretçisini C11 / C ++ 11'i alignas(64)veya otomatik depolamalı nesneler üzerinde doğru şekilde uygulamak için nasıl hizalayacağını bilir . Ve tabii ki GNU C__attribute((aligned((64)))
Peter Cordes

41

Gcc'de özniteliğin yığın değişkenleriyle çalışmamasına neden olan bir hata vardı . Aşağıda bağlantılı yama ile düzeltilmiş görünüyor. Aşağıdaki bağlantı aynı zamanda sorun için oldukça fazla tartışma içermektedir.

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

Yukarıdaki kodunuzu RedHat 5.7 kutusundan iki farklı gcc sürümüyle denedim: 4.1.2 ve probleminize benzer şekilde başarısız oldu (yerel diziler hiçbir şekilde 0x1000 bayt boundaies ile hizalanmadı). Daha sonra kodunuzu RedHat 6.3 üzerinde gcc 4.4.6 ile denedim ve kusursuz çalıştı (yerel diziler hizalandı). Myth TV ekibinin benzer bir sorunu vardı (yukarıdaki gcc yamasının çözdüğü görülüyordu):

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

Her neyse, gcc'de sonraki sürümlerde düzeltilmiş gibi görünen bir hata bulmuşsunuz gibi görünüyor.


3
Bağlantılı hataya göre gcc 4.6, bu sorunun tüm mimariler için tamamen düzeltildiği ilk sürümdü.
textshell

Bunun yanı sıra, yığın üzerinde hizalı değişken oluşturmak için gcc tarafından üretilen montaj kodu çok korkunç ve optimize edilmemiş. Öyleyse, hizalanmış değişkenleri çağırmak yerine yığına ayırmak mantıklı memalign()mı?
Jérôme Pouiller

13

Son GCC (4.5.2-8ubuntu4 ile test edildi), dizi düzgün şekilde hizalanmış olarak beklendiği gibi çalışıyor gibi görünmektedir.

Alırım:


Dizilerin yığında tahsis edildiği düşünüldüğünde, bu biraz şaşırtıcı - bu, yığının artık deliklerle dolu olduğu anlamına mı geliyor?
ysap

Veya yığını 16 bayt hizalı.
user7116

9

Hizalama tüm türler için etkili değildir. Öznitelikleri çalışırken görmek için bir yapı kullanmayı düşünmelisiniz:

Ve sonra okuyacaksınız:

Hangisini bekliyordun.

Düzenleme: @yzap tarafından gönderilen ve @Caleb Case yorumunun ardından, ilk sorun yalnızca GCC sürümünden kaynaklanmaktadır . İstekte bulunan kişinin kaynak koduyla GCC 3.4.6 ve GCC 4.4.1 karşılaştırmasını kontrol ettim:

Artık daha eski GCC sürümlerinin (4.4.1'den önceki bir yerde) hizalama patolojileri gösterdiği açıktır.

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

Not 2: Statik olmayan a [] 'yi main () içerisine getirmek ve GCC 3.4.6 ile derlemek yapı dizisinin hizalama yönergesini bozar ancak yapılar arasındaki 0x1000 mesafesini korur ... yine de kötü! (geçici çözümler için @zifre yanıtına bakın)


2
Zifre'nin yanıtladığı gibi, bu tür değil, sürümünüzde onu statik hale getirdiğiniz gerçeğidir.
ysap

@ysap, hem GCC versiyonu hem de çalışmasını sağlayan global tanımdı. Yorumunuz için teşekkürler! Düzeltmek için cevabı düzenledim. :)
levif
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.