Как структурируются в памяти на С++?

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

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

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

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

6 ответов

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

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

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

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

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

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

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

и §8.5.1/1:

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

и §9.2/12:

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

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

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

Поэтому (даже если ему предшествует a 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;
};

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


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

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


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

В стандарте нет гарантии. Я не буду зависеть от компиляторов с одинаковым выравниванием

У меня есть структура, где одна из ее члены должны быть выровнены по 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

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


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

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


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

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


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

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

licensed under cc by-sa 3.0 with attribution.