Я считаю, что проблема в том, что ваш массив находится в стеке, и что ваш компилятор слишком стар, чтобы поддерживать чрезмерно выровненные переменные стека. GCC 4.6 и более поздние версии исправили эту ошибку .
C11 / C ++ 11 alignas(64) float a[4];
Работает при любом выравнивании степени двойки.
То же самое и с GNU C в том __attribute__((aligned(x)))
виде, в котором вы его использовали.
(В C11 #include <stdalign.h>
для #define alignas _Alignas
: cppref ).
Но в вашем случае очень большого выравнивания по границе страницы 4k вам может не понадобиться его в стеке.
Поскольку при запуске функции указатель стека может быть любым, невозможно выровнять массив, не выделив намного больше, чем вам нужно, и не настроив его. (Компиляторы будут and rsp, -4096
или эквивалентны и не будут использовать какие-либо выделенные байты от 0 до 4088; ветвление относительно того, достаточно ли это пространство или нет, было бы возможно, но не выполняется, потому что огромные выравнивания намного превышают размер массива или других локальных переменных не являются нормальным случаем.)
Если вы переместите массив из функции в глобальную переменную, он должен работать. Еще вы могли бы сохранить ее как локальную переменную (что очень хорошо), но сделать ее static
. Это предотвратит его хранение в стеке. Помните, что оба этих способа не являются потокобезопасными или рекурсивно-безопасными, поскольку будет только одна копия массива.
С этим кодом:
#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
что и ожидается. С вашим исходным кодом я просто получаю случайные значения, как и вы.
alignas(64)
или что-то еще на объектах с автоматическим хранением. И, конечно же, GNU C__attribute((aligned((64)))
В gcc была ошибка, из-за которой атрибут, выровненный по стеку, не работал. Кажется, это исправлено патчем, указанным ниже. Ссылка ниже также содержит довольно много обсуждения проблемы.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16660
Я пробовал ваш код выше с двумя разными версиями gcc: 4.1.2 из окна RedHat 5.7, и он не удался, как и ваша проблема (локальные массивы никоим образом не выровнены по границам байтов 0x1000). Затем я попробовал ваш код с gcc 4.4.6 на RedHat 6.3, и он работал безупречно (локальные массивы были выровнены). У ребят из Myth TV была похожая проблема (которую, похоже, исправил вышеуказанный патч gcc):
http://code.mythtv.org/trac/ticket/6535
В любом случае, похоже, что вы нашли ошибку в gcc, которая, похоже, будет исправлена в более поздних версиях.
источник
memalign()
?Недавний 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
источник
Выравнивание действует не для всех типов. Вам следует подумать об использовании структуры, чтобы увидеть атрибуты в действии:
#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
Это то, чего вы ожидали.
Edit: Выдвинутый на @yzap и после @Caleb случая комментарий, исходная проблема связана с GCC версии только . Я проверил GCC 3.4.6 против GCC 4.4.1 с исходным кодом запрашивающего:
$ ./test_orig-3.4.6 0x7fffe217d200 0x7fffe217d204 0x7fffe217d208 0x7fffe217d20c $ ./test_orig-4.4.1 0x7fff81db9000 0x7fff81db9004 0x7fff81db9008 0x7fff81db900c
Теперь очевидно, что более старые версии GCC (где-то до 4.4.1) показывают патологии выравнивания.
Примечание 1. Предлагаемый мной код не отвечает на вопрос, который я понял как «выравнивание каждого поля массива».
Примечание 2: Внесение нестатического a [] внутрь main () и компиляция с GCC 3.4.6 нарушает директиву выравнивания массива структур, но сохраняет расстояние 0x1000 между структурами ... все еще плохо! (см. ответ @zifre для обходных путей)
источник