Переменные стека выравниваются с помощью атрибута ССЗ ((выравнивается(х)))?
у меня есть следующий код:
#include <stdio.h>
int
main(void)
{
float a[4] __attribute__((aligned(0x1000))) = {1.0, 2.0, 3.0, 4.0};
printf("%p %p %p %pn", &a[0], &a[1], &a[2], &a[3]);
}
и у меня следующие результаты:
0x7fffbfcd2da0 0x7fffbfcd2da4 0x7fffbfcd2da8 0x7fffbfcd2dac
почему адрес a[0]
не кратен 0x1000
?
что именно __attribute__((aligned(x)))
делает? Я неправильно понял этой объяснение?
я использую gcc 4.1.2.
4 ответа:
Я считаю, что проблема в том, что Ваш массив находится в стеке. Поскольку указатель стека может быть любым, когда функция запускается, нет способа выровнять массив, не выделяя намного больше, чем вам нужно, и не настраивая его. Если вы переместите массив из функции в глобальную переменную, он должен работать. Другое, что вы могли бы сделать, это сохранить его в качестве локальной переменной (что очень хорошо), но сделать это
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
это то, что ожидается. С вашим исходным кодом я просто получаю случайные значения, как и вы.
в gcc была ошибка, которая вызвала атрибут выравнивается, чтобы не работать с переменными стека. Это, кажется, исправлено с патчем, связанным ниже. Ссылка ниже также содержит довольно много дискуссий по этой проблеме.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16660
Я пробовал ваш код выше с двумя различными версиями gcc: 4.1.2 от RedHat 5.7 box, и это не удалось аналогично вашей проблеме (локальные массивы wre никоим образом не выровнен по границам 0x1000 байт). Затем я попробовал ваш код с gcc 4.4.6 on RedHat 6.3, и он работал безупречно (локальные массивы были выровнены). У людей Myth TV была аналогичная проблема (что патч gcc выше, казалось, исправил):
http://code.mythtv.org/trac/ticket/6535
в любом случае, похоже, вы нашли ошибку в gcc, которая, похоже, исправлена в более поздних версиях.
недавний 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
Alignement не является эффективным для всех типов. Вы должны рассмотреть возможность использования структуры, чтобы увидеть атрибуты в действии:
#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 Case, начальная проблема связана с версией GCC только. Я проверил на GCC 3.4.6 vs 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 нарушает директиву выравнивания массива struct, но сохраняет расстояние 0x1000 между структурами... все равно плохо ! (см. @zifre ответ для обходных путей)