Saya percaya masalahnya adalah bahwa array Anda ada di tumpukan, dan kompiler Anda terlalu tua untuk mendukung variabel tumpukan yang terlalu selaras. GCC 4.6 dan yang lebih baru memperbaiki bug itu .
C11 / C ++ 11 alignas(64) float a[4];
Hanya Berfungsi untuk semua kekuatan dari 2 keselarasan.
Begitu juga GNU C __attribute__((aligned(x)))
saat Anda menggunakannya.
(Di C11, #include <stdalign.h>
untuk #define alignas _Alignas
: cppref ).
Namun dalam kasus perataan yang sangat besar, ke batas halaman 4k, Anda mungkin tidak menginginkannya di tumpukan.
Karena penunjuk tumpukan bisa berupa apa saja saat fungsi dimulai, tidak ada cara untuk menyelaraskan array tanpa mengalokasikan lebih banyak dari yang Anda butuhkan dan menyesuaikannya. (Kompiler akan and rsp, -4096
atau setara dan tidak menggunakan salah satu dari 0 hingga 4088 byte yang dialokasikan; bercabang pada apakah ruang itu cukup besar atau tidak akan dimungkinkan tetapi tidak dilakukan karena perataan besar jauh lebih besar daripada ukuran array atau penduduk setempat lainnya bukan kasus normal.)
Jika Anda memindahkan array dari fungsi dan menjadi variabel global, itu akan berfungsi. Hal lain yang dapat Anda lakukan adalah menyimpannya sebagai variabel lokal (yang merupakan hal yang sangat bagus), tetapi buatlah static
. Ini akan mencegahnya disimpan di tumpukan. Berhati-hatilah karena kedua cara ini tidak aman untuk thread atau rekursi-aman, karena hanya akan ada satu salinan larik.
Dengan kode ini:
#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]);
}
Saya mengerti ini:
0x804c000 0x804c004 0x804c008 0x804c00c
itulah yang diharapkan. Dengan kode asli Anda, saya hanya mendapatkan nilai acak seperti yang Anda lakukan.
alignas(64)
atau apa pun pada objek dengan penyimpanan otomatis. Dan tentu saja GNU C__attribute((aligned((64)))
Ada bug di gcc yang menyebabkan atribut yang diselaraskan tidak berfungsi dengan variabel stack. Tampaknya sudah diperbaiki dengan tambalan yang ditautkan di bawah. Tautan di bawah ini juga berisi sedikit diskusi untuk masalah tersebut.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16660
Saya telah mencoba kode Anda di atas dengan dua versi gcc yang berbeda: 4.1.2 dari kotak RedHat 5.7, dan gagal serupa dengan masalah Anda (array lokal sama sekali tidak selaras pada batas 0x1000 byte). Saya kemudian mencoba kode Anda dengan gcc 4.4.6 di RedHat 6.3, dan itu bekerja dengan sempurna (array lokal diselaraskan). Orang-orang Myth TV memiliki masalah serupa (yang tampaknya diperbaiki oleh gcc patch di atas):
http://code.mythtv.org/trac/ticket/6535
Bagaimanapun, sepertinya Anda menemukan bug di gcc, yang tampaknya telah diperbaiki di versi yang lebih baru.
sumber
memalign()
?GCC terbaru (diuji dengan 4.5.2-8ubuntu4) tampaknya berfungsi seperti yang diharapkan dengan larik yang disejajarkan dengan benar.
#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]); }
Saya mendapat:
0x7ffffffefff0 0x7ffffffefff4 0x7ffffffefff8 0x7ffffffefffc 0x7ffffffef000 0x7ffffffef004 0x7ffffffef008 0x7ffffffef00c 0x7ffffffe0000 0x7ffffffe0004 0x7ffffffe0008 0x7ffffffe000c
sumber
Penjajaran tidak efektif untuk semua jenis. Anda harus mempertimbangkan menggunakan struktur untuk melihat atribut beraksi:
#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]); }
Dan kemudian, Anda akan membaca:
0x603000 0x604000 0x605000 0x606000
Itulah yang Anda harapkan.
Edit: Didorong oleh @yzap dan mengikuti komentar @Caleb Case, masalah awal adalah karena versi GCC hanya . Saya telah memeriksa GCC 3.4.6 vs GCC 4.4.1 dengan kode sumber pemohon:
$ ./test_orig-3.4.6 0x7fffe217d200 0x7fffe217d204 0x7fffe217d208 0x7fffe217d20c $ ./test_orig-4.4.1 0x7fff81db9000 0x7fff81db9004 0x7fff81db9008 0x7fff81db900c
Sekarang jelas bahwa versi GCC yang lebih lama (sebelum 4.4.1) menunjukkan patologi penyelarasan.
Catatan 1: Kode yang saya usulkan tidak menjawab pertanyaan yang saya pahami sebagai "menyelaraskan setiap bidang larik".
Catatan 2: Membawa non-statis a [] ke dalam main () dan mengkompilasi dengan GCC 3.4.6 memutus arahan penyelarasan dari array struct tetapi menjaga jarak 0x1000 antar struct ... masih buruk! (lihat jawaban @zifre untuk solusi)
sumber