URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 9174
[ Назад ]

Исходное сообщение
"Выравнивание данных (linux, gcc)"

Отправлено Crou , 28-Июн-11 16:17 
Подскажите, есть ли какой-нибудь стандартный способ определить размерность выравнивания данных? Т.е. нужно получить число, которому должен быт кратен размер выровненной структуры данных (может, макрос или хидер).

Содержание

Сообщения в этом обсуждении
"Выравнивание данных (linux, gcc)"
Отправлено me , 28-Июн-11 21:37 
> Подскажите, есть ли какой-нибудь стандартный способ определить размерность выравнивания
> данных? Т.е. нужно получить число, которому должен быт кратен размер выровненной
> структуры данных (может, макрос или хидер).

минимальный - sizeof(void *)


"Выравнивание данных (linux, gcc)"
Отправлено arturpub , 28-Июн-11 23:00 
> Подскажите, есть ли какой-нибудь стандартный способ определить размерность выравнивания
> данных? Т.е. нужно получить число, которому должен быт кратен размер выровненной
> структуры данных (может, макрос или хидер).

pow(2, ceil(log2(sizeof(x)))) вроде же


"Выравнивание данных (linux, gcc)"
Отправлено guest , 29-Июн-11 09:01 
у gcc есть __alignof__



"Выравнивание данных (linux, gcc)"
Отправлено Crou , 29-Июн-11 21:59 
Нашёл в /usr/include/bits/wordsize.h константу __WORDSIZE. Правда оно в битах, но тоже подходит.
А sizeof(void*) на других платформах (например arm atmega) корректно работает?


"Выравнивание данных (linux, gcc)"
Отправлено arturpub , 30-Июн-11 02:27 
> Нашёл в /usr/include/bits/wordsize.h константу __WORDSIZE. Правда оно в битах, но тоже
> подходит.
> А sizeof(void*) на других платформах (например arm atmega) корректно работает?

Корректно.

Слушай, граница выравнивания для разных типов данных и/или на разных платформах разная.
Например для х86:

sizeof(char) == 1, граница 1
sizeof(short) == 2, граница 2
sizeof(int) == 4, граница 4
sizeof(double) == 8, граница 8
sizeof(long double) == 10, граница 16, т.к. особо указано в интеловском мануале
sizeof(long long) == 8, граница 4, т.к. для не-FPU/SSE типов граница всегда <= 4

Невыровненные обращения ведут к:

а) падению производительности (засчет двух чтений вместо одного, ну или трех вместо двух)
б) фолту по невыравненному обращению, если включен таковой флаг в MSW/...

sizeof() структуры вообще может быть 57, и выравнивать ее больше, чем на long double, т.е. 16, не имеет смысла, кроме случаев, когда хочется попасть на границу кеш-линии, но это другая история, причем непереносимая даже внутри одной линейки процессоров.

Ты точно ту проблему решаешь?


"Выравнивание данных (linux, gcc)"
Отправлено Crou , 30-Июн-11 15:55 
>[оверквотинг удален]
> sizeof(short) == 2, граница 2
> sizeof(int) == 4, граница 4
> sizeof(double) == 8, граница 8
> sizeof(long double) == 10, граница 16, т.к. особо указано в интеловском мануале
> sizeof(long long) == 8, граница 4, т.к. для не-FPU/SSE типов граница всегда
> <= 4
> Невыровненные обращения ведут к:
> а) падению производительности (засчет двух чтений вместо одного, ну или трех вместо
> двух)
> б) фолту по невыравненному обращению, если включен таковой флаг в MSW/...

Это всё понятно.

> sizeof() структуры вообще может быть 57,

Честно говоря, я не представляю sizeof() структуры == 57, ну разве что "поучить" компилятор с помощью  #pragma pack или align директив. Тогда да, возможно всё. Я это не спора ради, так, мысли вслух.

> и выравнивать ее больше, чем на
> long double, т.е. 16, не имеет смысла, кроме случаев, когда хочется
> попасть на границу кеш-линии, но это другая история, причем непереносимая даже
> внутри одной линейки процессоров.
> Ты точно ту проблему решаешь?

Точно ту. Поясню. Есть шаряная память, в котороу я кладу различные структуры, а также массивы типа unsigned char с переменной длиной. Со структурами всё хорошо, они выровненные, никаких проблем не доставляют. А вот массивы unsigned char нужно ручками выравнивать (т.е. добавлять в конце несколько байт), чтобы в памяти следующие за этим массивом структуры или другие массивы после выполнения mmap() имели корректную адресацию. Ещё нюанс, софтина должна уметь работать на x86, x86_64 и arm. Поэтому и озадачился выравниваниями. (про atmega я спросил для общего развития, к вопросу она не имеет отношения).
В общем, спасибо за совет, буду использовать sizeof(void*).


"Выравнивание данных (linux, gcc)"
Отправлено arturpub , 30-Июн-11 16:33 
>> sizeof() структуры вообще может быть 57,

Например struct { char a[56]; char c; }, хотя согласен, пример идиотский.
Для struct { short a[28]; char c; } будет уже 58.
Для struct { int a[14]; char c; } будет 60, ну теперь-то идея понятна...

> В общем, спасибо за совет, буду использовать sizeof(void*).

...нужно в структуре визуально найти самый большой по sizeof'у член и выровнять по его границе. Если решение кажется error-prone, например есть структуры в структурах в структурах, можно использовать это:

union {
    intmax_t i;
    long double ld;
    void *p;
};

Ее sizeof есть максимальная граница выравнивания для ISO C99.


"Выравнивание данных (linux, gcc)"
Отправлено Crou , 30-Июн-11 17:51 
> union {
>     intmax_t i;
>     long double ld;
>     void *p;
> };
> Ее sizeof есть максимальная граница выравнивания для ISO C99.

Можно и так, но, думаю, можно обойтись просто sizeof(void*). Главная цель: чтобы при обращении к данным (структурам и массивам) из некоторой области shared memory, отображённой в адресное прастранство процесса, процесс обращался к корректным адресам. Т.е. чтобы в отображённом куске shared memory начала структур и массивов имели корректные адреса. Например, на arm'ах (может не на всех, точно не знаю) запрещено обращаться к нечётным адресам, arm генерит исключение при обращении к нечётным адресам. Может linux и умеет разруливать такие ситуации на arm, но не хотелось бы тратить на это процессорное время. Лучше софтину написать с учётом таких особенностей. Думаю, выравнивание данных до размера, кратного sizeof(void*), достаточно и универсально для всех современных архитектур. По крайней мере, для тех трёх, что я указал выше, точно подойдёт.


"Выравнивание данных (linux, gcc)"
Отправлено AHAHAC , 30-Июл-11 07:28 
>> union {
>>     intmax_t i;
>>     long double ld;
>>     void *p;
>> };
>> Ее sizeof есть максимальная граница выравнивания для ISO C99.
> Можно и так, но, думаю, можно обойтись просто sizeof(void*). Главная цель: чтобы
> при обращении к данным (структурам и массивам) из некоторой области shared
> memory, отображённой в адресное прастранство процесса, процесс обращался к корректным
> адресам.

Расскажите, что такая за программулина, которой нужно обращение к корректным адресам?!

Потом я Вам расскажу, единственное место в современном мире где используется выравнивание.
Нет, оно конечно не единственное, есть и более спец. задачи, но те люди которым это нужно
на сайте для лохов не пишут.


  
    


"Выравнивание данных (linux, gcc)"
Отправлено f00l , 01-Авг-11 11:08 
> Подскажите, есть ли какой-нибудь стандартный способ определить размерность выравнивания
> данных? Т.е. нужно получить число, которому должен быт кратен размер выровненной
> структуры данных (может, макрос или хидер).

Для выравнивания структуры обычно используют ключевое слово __attribute__
для запаковки структуры с параметром  ((__packed__))
пример:
  struct my_packed_struct __attribute__ ((__packed__))
  {
    char c;  
    short int i;
  };

такая структура занимает 3 байта.

больше информации http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Type-Attributes....