Выравнивание в gcc 3

Модератор: Модераторы разделов

Аватара пользователя
agbr
Сообщения: 486
ОС: openSUSE 10.2

Выравнивание в gcc 3

Сообщение agbr »

По каким правилам производится выравнивание в gcc:

Код: Выделить всё

struct {
char a;
short b;
int c;
long long d;
double e;
void* p;
}


существует ли правило для минимизации памяти, например размещать элементы в структуре по возрастанию размера, или по убыванию.
jabber: agbr@jabber.ru

против проприетарного ПО в GNU/Linux
Спасибо сказали:
Kirill Frolov
Сообщения: 6
ОС: Debian

Re: Выравнивание в gcc 3

Сообщение Kirill Frolov »

agbr писал(а):
30.08.2006 21:02
По каким правилам производится выравнивание в gcc:


По неопределённым. Такой ответ уставивает? Компиляторо-независимо.
Есть конечно прагмы, атрибуты и т.п. -- только на это полагаться -- дохлый номер.
Нужны форматированные данные -- форматируйте ручками по-байтово.

Код: Выделить всё

long long d;
double e;


Особо эти два типа нравятся мне. В плане совместимости в пределах разных платформ и компиляторов.

существует ли правило для минимизации памяти, например размещать элементы в структуре по возрастанию размера, или по убыванию.


Вообще, типично, располагается по-порядку. Я не уверен, но по-моему это описывается в соответствующем стандарте. Иначе ж половина софта поломается.
Спасибо сказали:
Аватара пользователя
ety
Сообщения: 358
ОС: Linux

Re: Выравнивание в gcc 3

Сообщение ety »

agbr писал(а):
30.08.2006 21:02
По каким правилам производится выравнивание в gcc:

по лучшим для целевой архитектуры адрессам (на x86, int и short обе будут по адрессам кратным 4-м), но "__attribute__ ((__packed__))" укажет alignment 1-го байта.
Образование - это вовсе не то, чему человека учили, а то, чему он научился.
-----
Время, необходимое на компиляцию пакета обратно пропорционально его полезности и важности его наличия в системе.
Спасибо сказали:
Аватара пользователя
Rmic
Сообщения: 87
ОС: Linux

Re: Выравнивание в gcc 3

Сообщение Rmic »

У меня такой вопрос по выравниванию:
Пусть имеется двоичный файл, в котором содержится записи по 12 байт с известными полями (см ниже описание структуры MyStruct). Записи располагаются в файле последовательно без всяких промежутков. Между полями (элементами записи) нет промежутков. Требуется прочитать файл в память и как-то обработать.
раньше, когда я писал по DOS на Borland C 3.1, я всегда считал, что это проще всего сделать так:

Код: Выделить всё

struct MyStruct
     {
     Byte Ident;
     Byte Date[3];
     Byte Time[3];
     long Value;
     Byte Checksum;
     };

FILE* InFile;
InFile = fopen (InFileName, "rb");
long InFileLength = filelength (InFile); // функция для определения размера файла
if ( InFileLength%sizeof (MyStruct) !=0) // проверка кратности размера файла размеру одной записи.
    {return -1; }
long EntriesNum = InFileLength/sizeof (MyStruct);
MyStruct* Buff = new MyStruct [EntriesNum]; // создаём массив структур
fread ((Byte*)(Buff),sizeof (MyStruct), EntriesNum, InFile ); // читаем файл в память
fclose (InFile)
/*здесь делаем какие-то действия*/
delete[] Buff;


В gcc, в момент, когда проверяется кратность размера файл размеру структуры, остаток не равер нулю и выполняется "return -1".
Я понимаю это так, что компилятор делает выравнивание элементов структуры, из-за чего sizoef (MyStruct) возвращает другое число (равное 16, если не ошибаюсь).

Но как тогда по-нормальному прочитать весь файл в память? Неужели нужно делать отдельный вызов fread для каждого элемента структуры???

Есть ещё другая ситуация, с которой пока не столкнулся, но предполагаю, что она тоже имеет место быть:
Пусть необходимо передавать через сокетное соединение (или через последовательный интерфейс) некоторые данные, которые в программе представлены в виде структур. Ведь функции отправки для сокетного соединения (или последовательного интерфейса) не знают, какую структуру я использую, и, как я понимаю, приводят передаваемый им указатель к (Byte*).
Так что же получается, здесь тоже нужно отдельно вызывать функции передачи данных для каждого элемента структуры? Получается, что если сделать приведение к (Byte*) и и вызвать функцию отправки для всего массива структур, то будут передаваться лишние байты???
А что, если нельзя отправлять данные по-отдельности???

Я где-то читал, что для gcc можно установить выравнивание до одного байта (кстати, подскажите как, если кто знает), но раз придумали выравнивание по 4 и 8 байтов и оно по умолчанию включено, значит в этом вероятно есть смысл.

Но как тогда обойти описанные выше проблемы, связанные с выравниванием?
Пингвин - друг человека!
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: Выравнивание в gcc 3

Сообщение RasenHerz »

хм... довольно таки интересная ситуация. я могу лишь набросать примерную схему работы.
почему бы не воспольщоваться , к примеру, таблицей со значениями смещений полей стуктуры? можно будет сначала передать клиенту размер таблицы, следом в виде массива байт передать саму таблицу, передать массив байт соответствующих структуре. клиенту необходимо сваять функцию, которая свяжет таблицу и переданный массив и вернет результат в виде структуры. если такое решение вас вполне устроит, то я могу набросать его примерную реализацию.
Спасибо сказали:
Аватара пользователя
Electronix
Сообщения: 53
ОС: Slackware, Suse, XP

Re: Выравнивание в gcc 3

Сообщение Electronix »

Rmic
Rmic писал(а):
18.05.2008 12:35
Но как тогда обойти описанные выше проблемы, связанные с выравниванием?

В обоих приложениях принудительно устанавливать смещение для структур, с помощью дириктивы #pragma pack, например. Выше в постах упоминается еще attribute(packed) - я подозреваю что это тоже самое практически, но я об это ничего не знаю, т.к. научился это делать через #pragma и когда учился никто мне о attribute packed ничего не говорил.

Код: Выделить всё

#pragma pack(push, 1)
struct MyStruct
{
    double dbl;
    int i;
    long long lng;
};
#pragma pack(pop)
We have no beginning, we have no end. We are infinite.
Спасибо сказали:
Аватара пользователя
Rmic
Сообщения: 87
ОС: Linux

Re: Выравнивание в gcc 3

Сообщение Rmic »

RasenHerz писал(а):
18.05.2008 12:58
хм... довольно таки интересная ситуация. я могу лишь набросать примерную схему работы.
почему бы не воспольщоваться , к примеру, таблицей со значениями смещений полей стуктуры? можно будет сначала передать клиенту размер таблицы, следом в виде массива байт передать саму таблицу, передать массив байт соответствующих структуре. клиенту необходимо сваять функцию, которая свяжет таблицу и переданный массив и вернет результат в виде структуры. если такое решение вас вполне устроит, то я могу набросать его примерную реализацию.

Так конечно можно, но мне такой подход видится не совсем целесообразным, поскольку при разработке клиент-серверных приложений часто имеется задача реализации конкретных протоколов, а не разработки новых. К тому же, имхо, нелогично привязывать протокол к внутренним особенностям работы компилятора или компьютера.

Electronix писал(а):
18.05.2008 13:23
Rmic
Rmic писал(а):
18.05.2008 12:35
Но как тогда обойти описанные выше проблемы, связанные с выравниванием?

В обоих приложениях принудительно устанавливать смещение для структур, с помощью дириктивы #pragma pack, например. Выше в постах упоминается еще attribute(packed) - я подозреваю что это тоже самое практически, но я об это ничего не знаю, т.к. научился это делать через #pragma и когда учился никто мне о attribute packed ничего не говорил.

Код: Выделить всё

#pragma pack(push, 1)
struct MyStruct
{
    double dbl;
    int i;
    long long lng;
};
#pragma pack(pop)



Попробовал так сделать в одной программе, которая работала неправильно из-за выравнивания. Поставил две указанных #pragma между кучей описаний структур. Заработало на ура! Спасибо.

А есть ли у кого-нибудь информация о том, как сильно выравнивание влияет на производительность программы?
Пингвин - друг человека!
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: Выравнивание в gcc 3

Сообщение RasenHerz »

Rmic писал(а):
18.05.2008 13:57
Так конечно можно, но мне такой подход видится не совсем целесообразным, поскольку при разработке клиент-серверных приложений часто имеется задача реализации конкретных протоколов, а не разработки новых. К тому же, имхо, нелогично привязывать протокол к внутренним особенностям работы компилятора или компьютера.

cорри, уточню :
таблица вида: "имя поля" - "тип параметра" - "длина параметра" - "смещение в массиве переданных байт"
по-моему такой подход, не привяжет протокл не к особенностям компилятора/клиентской/серверной машины потому что содержит имя поля, его тип, что предупреждает возможность неправильного присвоения типов (к примеру, int -> char[sizeof(int)] ); следом за типом идет его размер, что исключит неправильное заполнение струтур(в случае если клиентская и серверная машина имеют разную архитектуру).

на деле подход с упаковкой структур не оправдывает себя, так как ,во-первых, нет гарантии что структура на клиентском компьютере будет упакована так же как и на сервере, во-вторых, размер структур на клиенте и на сервере может значительно отличаться. и как следствие - без передачи дополнительных данных, структуру по сети передавать не то что нельзя, а скорее нецелесообразно.
Спасибо сказали:
Аватара пользователя
Electronix
Сообщения: 53
ОС: Slackware, Suse, XP

Re: Выравнивание в gcc 3

Сообщение Electronix »

RasenHerz
Согласен. Если планируется использовать на алюблютно разных ОС, то для этого придется протокол писать (или взять готовый) и через него передавать данные. Тогда же еще придется реализовывать кодирование и декодирование запросов/ответов.
We have no beginning, we have no end. We are infinite.
Спасибо сказали:
MiK13
Сообщения: 1289
ОС: Linux Debian

Re: Выравнивание в gcc 3

Сообщение MiK13 »

Лично я стараюсь создавать структуры, которые бы не требовали никакого специального выравнивания. Т.е. поля, простой элемент которого имеет размер 2 байта должны находиться чётному смыщению с начала структуры. Если размер 4 байта -- смещение должно быть кратным 4.
Но, на всякий случай, ставлю в свои программы (для gcc) в начало
#pragma pack(1)
Что касается увеличения быстродействия при наличии выравнивания... раньше это действительно было, т.е. требовало меньше операций для извлечения операндов из памяти или записи в неё. Более того, некоторые процессоры не допускали чтение/запись слов по нечётным адресам. Например, на процессоре PDP-11 такое действие вызывало прерывание аналогичное обращение к несуществующей ячейке (по-моему, некоторые процессоры SUN могут вести себя аналогично).
Я бы посоветовал при разработки структур это учитывать заранее.
Но что касается размеров отдельных полей -- надо смотреть описание процессоров.
По этой причине я в программах для x86 не использую в структурах тип int (или integer в Pascal) -- либо short, либо long.
Правда, недавно узнал, что есть процессоры (точнее, компиляторы для них), в которых тип short имеет размер 2 байта, тип int -- 4 байта, а тип long -- 5 байтов.
Ещё надо учитывать порядок байтов -- в одних процессорах сначала идёт младший байт, в других -- старший. Причём, я не знаю, что чаще используется.
Спасибо сказали: