Mayor
Специалист
Offline
|
|
« : 04-05-2004 08:24 » |
|
В целях оптимизации под i386 , мне требуется заставить компилятор автоматически при объявлении структуры задавать смещение некоторых полей кратными 4 или 8 байтам и также для массивов требуются структуры размером кратные 4 или 8 , например :
struct r_elem{ c_elem a1; unsigned char data1[max_t]; unsigned char data2[max_r]; BYTE flags; unsigned int size; }
где c_elem структура произвольного размера в целях оптимизации помещается в начало , max_t max_r могут от версии к версии варьировать , но смещения от начала r_elem до data1 и data2 должны быть кратны 8 байтам ,смещение flags не имеет значения, смещение size д.б. кратно 4 байтам при этом размер структуры д.б. кратен 8
Как об этом сообщить компилятору ?
|
|
|
Записан
|
1n c0de we trust
|
|
|
npak
|
|
« Ответ #1 : 05-05-2004 09:38 » |
|
Широко распространённый в мире C приём: сделать union с двумя полями. Первое поле твоё, второе -- массив того размера, который нужен для выравнивания следующего поля. В примере ниже структура с двумя полями данных, причём второе выровнено на границу 64 бита. Первое поле сидит внутри юниона, поэтому для него создаём макрос для удобства доступа. struct my_struct { union { shord _my_field_1; /* My data field */ int8_t align_1[8]; /* Alignment 64 bits */ } _u1; int my_field_2; /* This field is aligned to 64 bits */ };
#define my_field_1 _u1._my_aligned_field
|
|
« Последнее редактирование: 25-11-2007 20:08 от Алексей1153++ »
|
Записан
|
|
|
|
darkelf
Молодой специалист
Offline
|
|
« Ответ #2 : 05-05-2004 14:07 » |
|
Вариант с #pragma #pragma pack(push, 4) struct my_struct { short my_field_1; /* My data field */ int my_field_2; /* This field is aligned to 64 bits */ }; #pragma pack(pop)
|
|
« Последнее редактирование: 25-11-2007 20:08 от Алексей1153++ »
|
Записан
|
|
|
|
npak
|
|
« Ответ #3 : 05-05-2004 14:29 » |
|
По-моему, в данном примере для выравнивания на 8 байт должно быть К сожалению, это нестандартная фича компилятора от майкрософт. Если в планах есть перенос на другую операционную систему/другой комилятор, то такой способ задать выравнивание может осложнить жизнь.
|
|
« Последнее редактирование: 25-11-2007 20:23 от Алексей1153++ »
|
Записан
|
|
|
|
Anonymous
Гость
|
|
« Ответ #4 : 06-05-2004 16:40 » |
|
К сожалению, это нестандартная фича компилятора от майкрософт. Если в планах есть перенос на другую операционную систему/другой комилятор, то такой способ задать выравнивание может осложнить жизнь.
в gсс v3.2 тоже работает, так что не такая уж нестандартная.
|
|
|
Записан
|
|
|
|
npak
|
|
« Ответ #5 : 06-05-2004 17:37 » |
|
К сожалению, это нестандартная фича компилятора от майкрософт. Если в планах есть перенос на другую операционную систему/другой комилятор, то такой способ задать выравнивание может осложнить жизнь.
в gсс v3.2 тоже работает, так что не такая уж нестандартная. А у меня не работает. gcc на эту прагму не ругается, но игнорирует. В примере с union выравнивается правильно.
|
|
|
Записан
|
|
|
|
npak
|
|
« Ответ #6 : 06-05-2004 20:56 » |
|
В gcc есть свой способ указывать выравнивание для полей структур -- атрибут aligned struct my_struct_aligned { short aligned_field_1; int aligned_field_2 __attribute__((aligned (8))); }; Для примера, вот программа для gcc #include <stdio.h>
#pragma pack(push, 8) struct my_struct_pack { short pack_field_1; int pack_field_2; }; #pragma pack(pop)
struct my_struct_aligned { short aligned_field_1; int aligned_field_2 __attribute__((aligned (8))); };
struct my_struct_union { union { short union_1_field_1; /* My data field */ char align_1[8]; /* Alignment 64 bits */ } _u1; int union_field_2; /* This field is aligned to 64 bits */ };
#define union_field_1 _u1.union_1_field_1 int ptr_diff(void * p1, void * p2) { return (char *)p2 - (char *)p1; }
int main() { struct my_struct_aligned sa; struct my_struct_union su; struct my_struct_pack sp;
printf( "pack: %d\n", ptr_diff( &(sp.pack_field_1), &(sp.pack_field_2) ) ); printf( "aligned: %d\n", ptr_diff( &(sa.aligned_field_1), &(sa.aligned_field_2) ) ); printf( "union: %d\n", ptr_diff( &(su.union_field_1), &(su.union_field_2) ) ); return 0; } У меня под gcc 3.3 получается такой вывод: pack: 4 aligned: 8 union: 8 Получается, что gcc игнорирует #pragma pack. С другой стороны, ms vc обругает gcc-ный атрибут. Выходит, что использование union -- наиболее переносимый подход из представленных.
|
|
« Последнее редактирование: 25-11-2007 20:24 от Алексей1153++ »
|
Записан
|
|
|
|
npak
|
|
« Ответ #7 : 06-05-2004 20:56 » |
|
В gcc есть свой способ указывать выравнивание для полей структур -- атрибут aligned struct my_struct_aligned { short aligned_field_1; int aligned_field_2 __attribute__((aligned (8))); }; Для примера, вот программа для gcc #include <stdio.h>
#pragma pack(push, 8) struct my_struct_pack { short pack_field_1; int pack_field_2; }; #pragma pack(pop)
struct my_struct_aligned { short aligned_field_1; int aligned_field_2 __attribute__((aligned (8))); };
struct my_struct_union { union { short union_1_field_1; /* My data field */ char align_1[8]; /* Alignment 64 bits */ } _u1; int union_field_2; /* This field is aligned to 64 bits */ };
#define union_field_1 _u1.union_1_field_1 int ptr_diff(void * p1, void * p2) { return (char *)p2 - (char *)p1; }
int main() { struct my_struct_aligned sa; struct my_struct_union su; struct my_struct_pack sp;
printf( "pack: %d\n", ptr_diff( &(sp.pack_field_1), &(sp.pack_field_2) ) ); printf( "aligned: %d\n", ptr_diff( &(sa.aligned_field_1), &(sa.aligned_field_2) ) ); printf( "union: %d\n", ptr_diff( &(su.union_field_1), &(su.union_field_2) ) ); return 0; } У меня под gcc 3.3 получается такой вывод: pack: 4 aligned: 8 union: 8 Получается, что gcc игнорирует #pragma pack. С другой стороны, ms vc обругает gcc-ный атрибут. Выходит, что использование union -- наиболее переносимый подход из представленных.
|
|
« Последнее редактирование: 25-11-2007 20:34 от Алексей1153++ »
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #8 : 07-05-2004 06:36 » |
|
Cамым переносимым методом обычно было #ifdef __WIN32__ ... #else ... #endif
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Mayor
Специалист
Offline
|
|
« Ответ #9 : 19-05-2004 02:01 » |
|
Union можно использовать, когда размер структуры известен заранее ,и это действительно удобно в плане переносимости .
Ища в MSDN aligned я наткнулся на __declspec(align(#)) , описания gcc у меня нет , но судя по смыслу это тоже самое, так что в плане переносимости можно воспользоваться советом RXL . Кстати в плане совместимости, насколько gcc совместим с lcc-win32 ?
А вот чем заменить pack я не знаю , но пока проблема переносимости не стоит , так что буду использовать в msvc ...
|
|
|
Записан
|
1n c0de we trust
|
|
|
npak
|
|
« Ответ #10 : 19-05-2004 10:41 » |
|
Mayor, ты можешь использовать для выравнивания union макросы #define ADJUST_TO_MULTIPLE(n, base) ((((n) + (base) - 1)/(base))*(base)) #define ALIGN_TO_8(n) (ADJUST_TO_MULTIPLE(n, 8))
union { struct some_struct _u1_value1; unsigned char _u1_align[ALIGN_TO_8(n)]; } u1; для pack в gcc есть атрибут packed. Судя по инфе в интернете, lcc нацелен на строгую поддержку ansi c. В нём, похоже, не поддерживаются расшиения gcc.
|
|
« Последнее редактирование: 25-11-2007 20:34 от Алексей1153++ »
|
Записан
|
|
|
|
Mayor
Специалист
Offline
|
|
« Ответ #11 : 21-05-2004 01:41 » |
|
Я думаю вариант с union на произвольных структурах несколько сложноват . Зато предложенные вами alig% , pack% и #ifdef удовлетворяют всем требованиям и являются кроссплатформенными . Всем спасибо за помощь , вопрос полностью разрешен P.S. ну чтож попробую заценить через недельку lcc, все равно я с gcc пока не работаю , таким образом обратная совместимость пока мне не нужна
|
|
|
Записан
|
1n c0de we trust
|
|
|
|