Как понять вывод иерархии fdump-class

Я играю с опцией компилятора fdump-class-иерархии, но я не знаю, как я могу понять вывод. Что означают «размер», «выравнивание», «базовый размер» и «выравнивание базы» и как они учитываются? Спасибо!

Когда код:

class A
{
public:

private:
double m_nothing;
int m_number;
};

Выход:

Class A
size=16 align=8
base size=16 base align=8
A (0x406c690) 0

Но, если я немного изменю класс:

class A
{
public:

private:
int m_number;
double m_nothing;
};

вывод будет:

Class A
size=16 align=8
base size=12 base align=8
A (0x406c690) 0

5

Решение

size а также align Размер и выравнивание класса, когда используется как полный тип. То есть, если вы создаете объекты, полный тип которых является этим типом (например, определение переменных этого типа или использование этого типа с new).

Размер — это просто количество байтов, которое он занимает. Так size=16 означает, что при использовании в качестве завершенного типа он всегда занимает 16 байтов.

Выравнивание говорит вам, где объект может быть размещен: align=8 означает, что адрес объекта должен быть целым, кратным 8.

base size а также base align дать размер и выравнивание в случае, если класс используется в качестве базового класса. Причина, по которой они различаются, заключается в том, что стандарт C ++ позволяет объектам использовать меньше отступов при использовании в качестве базового класса.

Итак, давайте посмотрим конкретно на ваш пример (я предполагаю, что у вас есть int перед double в первом случае). Я также опускаю public а также private потому что здесь они ничего не меняют (если у вас были как открытые, так и частные члены данных, они мог в принципе что-то изменить, но я не знаю, пользуется ли какой-либо компилятор этим преимуществом). Я также угадываю размер и выравнивание int а также double (на самом деле значения, которые я предполагаю, довольно распространенный выбор, и объясняют значения, которые вы получаете).

Так что в первом случае (я предполагаю) у вас есть

class A
{
int m_number;
double m_nothing;
};

Сейчас int имеет размер и выравнивание 4и двойной имеет размер и выравнивание 8,

Итак, давайте выполним работу компилятора и создадим наш класс.

Во-первых, у нас есть m_number, который занимает 4 байта. Мы должны поместить членов в указанном порядке, поэтому m_number идет в начале A:

iiii

До сих пор у нас есть размер 4 (четыре байта для int) и выравнивание 4 (потому что int имеет выравнивание 4). Но теперь мы должны добавить двойной (размер и выравнивание 8). Так как непосредственно после int мы находимся по (относительному) адресу 4, мы не правильно выровнены по двойному, поэтому мы должны добавить 4 набивка байты (которые я отмечу *), чтобы получить кратное 8. Таким образом, мы получаем для нашего класса:

iiii****dddddddd

Теперь, если класс используется в качестве базового класса, мы закончили. Таким образом, мы имеем base size=16 а также base align=8 (нам нужно выравнивание 8, чтобы правильно выровнять двойник).

Для законченного объекта есть еще одно соображение: стандарт требует, чтобы в массивах объекты следовали друг за другом без промежутка между ними. То есть первый байт после объекта должен быть правильно выровнен для следующего объекта. Что в конечном итоге означает, что размер всего объекта должен быть кратным его выравниванию.

Теперь найденный нами макет объекта уже удовлетворяет этому требованию. Поэтому мы можем использовать его без изменений и для всего объекта. Поэтому мы получаем size=16 а также align=8 для полного объекта.

Теперь рассмотрим случай, когда заказ полностью изменен:

class A
{
double m_nothing;
int m_number;
};

Теперь мы должны начать с double:

dddddddd

Далее мы должны добавить int, Оказывается, следующее свободное место уже правильно выровнено для intпоэтому мы можем просто добавить его:

ddddddddiiii

Теперь для использования в качестве базового объекта мы готовы. Как видите, нам потребовалось всего 12 байтов, поэтому base size=12, Конечно для double чтобы быть правильно выровненным, объект снова должен начинаться с адреса, кратного 8. Поэтому мы имеем base align=8,

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

ddddddddiiii****

Как видите, теперь нам нужно 16 байтов, таким образом size=16, У нас все еще есть align=8 из-за двойника.

Обратите внимание, что требование выравнивания может существенно повлиять на размер класса. Рассмотрим, например, следующие два типа:

struct S1
{
char c1;
double d1;
char c2;
double d2;
char c3;
};

struct S2
{
double d1;
double d2;
char c1;
char c2;
char c3;
};

Хотя оба содержат одинаковых членов, S1 будет с размерами и выравниваниями выше иметь общий (не базовый) размер 40, в то время как общий размер S2 будет всего 24. Действительно, объекты типа S1 будет, как законченный объект, выглядеть

c*******ddddddddc*******ddddddddc*******

в то время как те, типа S2 будет выглядеть

ddddddddddddddddccc*****

Итак, суть в том, что члены с самым высоким требованием выравнивания всегда должны стоять на первом месте.

Также обратите внимание, что sizeof возвращает размер завершенных объектов, то есть то, что вызывает дамп иерархии классов size,

12

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]