Как структуры размечаются в памяти в C++?

Являются путем структуры C++, размечаются установленные стандартом или по крайней мере распространенные через компиляторы?

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

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

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

8
задан ngoozeff 11 August 2010 в 02:54
поделиться

5 ответов

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

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

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

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

Это тип POD, но публикация : между 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-структуры, соответствующим образом преобразованный с использованием a reinterpret_cast указывает на его начальный член ...

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

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

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

Следовательно, если у вас есть что-то вроде:

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

Это требуется, чтобы макет был совместим с:

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

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

13
ответ дан 5 December 2019 в 06:36
поделиться

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

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

5
ответ дан 5 December 2019 в 06:36
поделиться

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

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

0
ответ дан 5 December 2019 в 06:36
поделиться

Так устроены структуры 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», чтобы гарантировать правильную работу. Может быть, и не нужно, но это определенно сработает.

4
ответ дан 5 December 2019 в 06:36
поделиться

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

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

2
ответ дан 5 December 2019 в 06:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: