вторник, 27 января 2009 г.

Сюрприз C/C++ структуры (Data structure alignment)

Казалось бы, что размер структуры в C/C++ элементарно равен сумме её частей(прим. лично я так думал).

struct Vector {
int x;
int y;
int z;
};


Большинство скажет: sizeof(Vector) == 3 * sizeof(int) . int как правило равен 4 байтам, т.е. данная структура по идее должна занимать 12 байт. Теоретически - это так. Но (!) практически - как выставите опции компилятора.

Данная "фича" называется "Выравнивание" или "Data Structure Alignment". Она выравнивает размер структуры данных до кратного некоторому числу(естесственно степени 2), например 2, 4, 8. Располагает данные в нужном порядке, а между ними размещает "заполнитель" :) пустоту вобщем.

Для чего это нужно? Здесь описано. Вкратце, это оптимизация данных для ускорения доступа. Как всегда, есть некая точка равновесия между размером данных и скоростью доступа к ним. Короче, должно быть использовано с умом и пониманием.

К каким последствиям это может привести? Последствием может быть неправильное чтение/запись структуры, если оно чётко определено стандартом. Это могут быть различные заголовки файлов, данные и т.д. Такое бы уже не прошло:
read(file, &my_struct, sizeof(my_struct));
write(file, &my_struct, sizeof(my_struct));


Для меня эта новость была неожиданной и привела к нескольким часам выяснения, почему заголовок BMP файла читается неправильно. Оказалось, что IDE Borland Turbo C++ по умолчанию выставлял опцию компилятора - выравнивание в 4 байта.
Вообще заголовок BMP файла должен был занимать 14 байт, но sizeof(BMPHeader) упорно возвращал 16! И из-за этого я никак не мог прочитать смещение до самих данных.
Выставить нужно смещение можно либо выставив опции компилятора, либо директивами:
#pragma pack(push)  /* push current alignment to stack */
#pragma pack(1) /* set alignment to 1 byte boundary */

/** твоя структура */

#pragma pack(pop) /* restore original alignment from stack */

p.s.: компилятор borland и IDE Borland TurboC++ используются сугубо по требованию преподавателя.

1 комментарий:

  1. Я для себя сделал один вывод:
    Не пользоваться компилятором от
    IDE Borland Turbo C++

    ОтветитьУдалить