2013-07-23 3 views
3

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

Когда код:

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 
+3

Я думаю, вы забыли немного изменить класс. – chris

+0

О, извините! Во втором примере я заменил две переменные-члены. – user19840919

ответ

8

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 (четыре байта для междунар) и выравнивание 4 (потому что ИНТ имеет выравнивание 4). Но теперь мы должны добавить двойной (размер и выравнивание 8).Поскольку непосредственно после int мы находимся на (относительном) адресе 4, мы неправильно выровнены для двойника, поэтому нам нужно добавить 4 padding байт (что я буду отмечать *), чтобы получить кратное 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.

+0

Отличный ответ. Мне кажется, что каждый получает меньшие классы, если сначала объявляет крупнейших участников. Я прав? –

+0

Это не размер, а выравнивание, которое здесь имеет значение. Например, 'struct X {char s [17]; } 'больше, чем' double', но имеет выравнивание 1 (и размер, который не кратен выравниванию double). Строка, содержащая 'X', за которой следует' double', за которой следует 'char', будет больше (больше отступов), чем если бы двойной был первым. – celtschk