sizeof дает неожиданный результат для моей структуры

В моем коде есть такая структура:

struct BlockDescriptor
{
    struct BlockDescriptor * pNext;
    bool _isFree;
};

и я склонен полагать, что его размер равен 4 + 1 = 5 (4 для указателя и 1 для bool), но по какой-то причине sizeof(struct BlockDescriptor) возвращает 8! Может кто-нибудь сказать мне, почему?

Это из-за проблем с упаковкой, что 5 округляется до кратного 4 (поскольку 32 бита - это то, с чем большинство компьютеров наиболее комфортно), и есть ли способ заставить его использовать истинный размер (если это на самом деле истинный размер). размер) ?


person angryInsomniac    schedule 17.03.2013    source источник
comment
Отступ между pNext и _isFree. Вы можете принудительно выполнить упаковку с помощью механизмов, специфичных для компилятора.   -  person cnicutar    schedule 18.03.2013
comment
поместите #pragma pack (1) перед определением структуры.   -  person Luka Rahne    schedule 18.03.2013
comment
Почему для вас важно, что возвращает sizeof(struct BlockDescriptor)?   -  person Philip Kendall    schedule 18.03.2013
comment
@LukaRahne Спасибо, что сработало   -  person angryInsomniac    schedule 18.03.2013
comment
@PhilipKendall Потому что я пишу пул памяти, и каждый потерянный байт драгоценен   -  person angryInsomniac    schedule 18.03.2013
comment
изменить порядок членов в struct: bool; struct *; и вы можете получить 5 байтов, но это зависит от компилятора   -  person spin_eight    schedule 18.03.2013
comment
См. Вопросы 2.12 и 2.13 в FAQ по comp.lang.c; в данном конкретном случае это применимо как к C, так и к C ++.   -  person Keith Thompson    schedule 18.03.2013


Ответы (3)


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

Первый член данных - это указатель, который в вашем случае требует 4 байта памяти. Тогда, хотя другой член - это char, которому требуется только 1 байт памяти, есть заполнение, кратное 4, но причина не в том, что «32 бита - это то, с чем большинству компьютеров удобнее всего» как вы говорите, а потому что 4 - это размер самого большого элемента данных.

Обычно существует директива pragma, позволяющая указать доступное настраиваемое выравнивание. В Visual Studio есть #pragma pack, который может помочь вам в этом деле. Просто убедитесь, что вы знаете, что делаете. Хотя вы минимизируете использование памяти, это может отрицательно повлиять на производительность вашего кода.

Для получения дополнительной информации просмотрите связанные вопросы:
Как минимизировать использование памяти структурным типом? < br> Как sizeof вычисляет размер структур
Должен ли размер структуры быть точным кратным выравниванию этой структуры?
или даже Определение выравнивания структур C / C ++ по отношению к их элементам

person LihO    schedule 17.03.2013
comment
Ага, выравнивание определяется размером самого большого элемента данных, я не могу поверить, что забыл об этом: P, и если бы мой профессор программирования увидел, что я бы получил основательный удар :) - person angryInsomniac; 18.03.2013

Публикация ответа любезно предоставлена: Лука Ране и cnicutar

Между pNext и _isFree есть Padding. Вы можете принудительно использовать "упаковку" с помощью механизмов, специфичных для компилятора, поместив #pragma pack (1) перед определением структуры.

person angryInsomniac    schedule 17.03.2013
comment
Заполнение с большей вероятностью будет после _isFree, чтобы заполнить размер структуры до 8 байтов. - person Pete Becker; 18.03.2013
comment
@PeteBecker Ага, _isFree выравнивается по 4, что является выравниванием структуры, поскольку ее самый большой член данных имеет размер 4. - person angryInsomniac; 18.03.2013

Когда ЦП обращается к памяти для выборки элемента данных (или члена структуры), он фактически отправляет запрос контроллеру памяти, который выполняет некоторые уловки, чтобы DRAM выглядело как хорошо структурированное хранилище данных. На самом деле DRAM - это группа ячеек, расположенных в M строках по N бит в каждой (где N может быть около тысячи).

Зная, что большинство архитектур обрабатывают 4, 8, 16 или 32 (а иногда и более крупные) бита за раз, контроллеры памяти оптимизированы для выборки с адресов, кратных 4. Что происходит, когда вы выбираете один байт с адреса abcd1002? Что ж, контроллер памяти извлекает четыре байта из адреса abcd1000, затем сдвигает их, чтобы получить третий байт (помните, это 0, 1, затем 2), и дает вам ваш паршивый невыровненный байт. Таким образом, выборка с выровненного адреса всегда быстрее, чем с невыровненного.

Сознавая этот факт, компиляторы агрессивно оптимизируют скорость, заполняя структуры данных так, чтобы они располагались в удобном для памяти виде.

Надеюсь, что это дает важный взгляд на архитектуру компьютера по этому вопросу. Я не видел, чтобы об этом упоминалось ни в одном из текущих ответов, поэтому мне захотелось добавить свои 0,02 доллара.

person Rahul Banerjee    schedule 17.03.2013