Как структуры расположены в памяти в C ++? - PullRequest
8 голосов
/ 11 августа 2010

Способ размещения структур C ++ установлен стандартом или, по крайней мере, общий для компиляторов?

У меня есть структура, в которой один из ее членов должен быть выровнен по 16-байтовым границам, и этобыло бы проще, если бы я мог гарантировать порядок полей.

Кроме того, для невиртуальных классов адрес первого элемента также может быть адресом структуры?

Iменя больше всего интересуют GCC и MSVS.

Ответы [ 6 ]

13 голосов
/ 11 августа 2010

C и C ++ гарантируют, что поля будут размещены в памяти в том же порядке, в котором вы их определили. Для C ++ это гарантировано только для типа POD 1 (все, что было бы допустимо в качестве структуры C [Правка: C89 / 90 - не, например, VLA C99], также будет считаться POD) .

Компилятор может свободно вставлять отступы между членами и / или в конце структуры. Большинство компиляторов дают вам возможность контролировать это (например, #pragma pack(N)), но это зависит от компилятора.

1 Ну, есть один угловой случай, о котором они не думали, когда он не гарантирован для типа POD - спецификатор доступа нарушает гарантию заказа:

struct x { 
    int x;
    int y;
public:
    int z;
};

Это тип POD, но public: между y и z означает, что они теоретически могут быть переупорядочены. Я почти уверен, что это чисто теоретический подход - я не знаю ни одного компилятора, который бы переупорядочивал члены в этой ситуации (и если память не подведет меня даже хуже, чем обычно сегодня, это исправлено в C ++ 0x).

Редактировать: соответствующие части стандарта (по крайней мере, большинство из них) - §9 / 4:

POD-структура - это агрегатный класс, который не имеет энергонезависимой члены данных типа указатель на член, не POD-структура, не POD-союз (или массив таких типов) или ссылка, и не имеет Определяемый пользователем оператор копирования копии и не определяемый пользователем деструктор.

и §8.5.1 / 1:

Агрегат - это массив или класс (раздел 9) без пользовательских заявленные конструкторы (12.1), нет частных или защищенных члены статических данных (пункт 11), без базовых классов (пункт 10) и без виртуальных функций (10.3).

и §9.2 / 12:

... порядок размещения нестатических данных элементов разделенный спецификатором доступа не указан (11.1).

Хотя это несколько ограничено §9.2 / 17:

Указатель на объект POD-struct, соответствующим образом преобразованный с использованием reinterpret_cast, указывает на его начальный член ...

Следовательно, (даже если перед ним стоит public:, первый определяемый вами элемент должен стоять первым в памяти. Другие члены, разделенные спецификаторами public:, теоретически могут быть переставлены.

Я должен также указать, что есть место для споров по этому поводу. В частности, в §9.2 / 14 есть также правило:

Два типа POD-struct (раздел 9) совместимы с макетом, если они имеют одинаковое количество нестатических элементов данных, а соответствующие элементы нестатических данных (по порядку) имеют типы, совместимые с макетом (3.9).

Поэтому, если у вас есть что-то вроде:

struct A { 
    int x;
public:
    int y;
public:
    int z;
};

Требуется совместимость макета с:

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

Я почти уверен, что это было / было предназначено для обозначения того, что члены двух структур должны быть одинаково размещены в памяти. Поскольку второй явно не может переставлять своих членов, первый тоже не должен быть. К сожалению, стандарт никогда не определяет, что означает «совместимость с макетом», что делает аргумент в лучшем случае довольно слабым.

5 голосов
/ 11 августа 2010

C ++ наследует от c потребность / желание эффективно работать на многих платформах и поэтому оставляет определенные вещи на усмотрение компилятора. Помимо обязательного отображения элементов в указанном порядке, это один из них.

Но многие компиляторы поддерживают #pragma s и опции, позволяющие установить контроль над упаковкой. Смотрите документацию вашего компилятора.

4 голосов
/ 11 августа 2010

Как устроены структуры C ++ устанавливается стандартом или, по крайней мере, общий для компиляторов?

Нет гарантии в стандарте. Я бы не зависел от компиляторов, имеющих одинаковое выравнивание

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

Компиляторы не будут изменять порядок полей.

Вот несколько ссылок о том, как установить их для GCC и MSVC:
Для GCC: http://developer.apple.com/mac/library/documentation/DeveloperTools/gcc-4.0.1/gcc/Structure_002dPacking-Pragmas.html
MSVC: http://msdn.microsoft.com/en-us/library/ms253935(VS.80).aspx и http://msdn.microsoft.com/en-us/library/2e70t5y1(VS.80).aspx

Я бы оставил их как структуры и использовал бы внешний "C", чтобы убедиться, что он работает должным образом. Может быть, не нужно, но это определенно сработает.

2 голосов
/ 11 августа 2010

C struct s (и P ++ C ++, для совместимости) требуется стандартом для последовательной компоновки .

Единственное различие между компиляторами - выравнивание, но, к счастью, поддержка MSVC и GCC #pragma pack.

1 голос
/ 30 августа 2012

Если вы хотите видеть структуру памяти всех типов классов в памяти под MSVC, добавьте переключатель /d1reportAllClassLayout в командную строку компилятора.

Если вы хотите увидеть, как выглядит один класс, добавьте /d1reportSingleClassLayoutNNNNN, где NNNNN - это имя класса.

0 голосов
/ 11 августа 2010

Структуры располагаются последовательно в памяти. Однако способ их выравнивания в памяти зависит от операционной системы.

Для вещей размером более 4 байт существует разница между Windows и Linux. Linux выравнивает их, как если бы они были 4 байта, поэтому, например, двойной (8 байт) может начинаться с p + 4, p + 8, p + 12 и т. Д., Где p - начало структуры. В Windows двойной (8 байт) должен начинаться с адреса, кратного 8, поэтому p + 8, p + 16, p + 24 и т. Д.

...