Являются путем структуры C++, размечаются установленные стандартом или по крайней мере распространенные через компиляторы?
У меня есть структура, где один из ее участников должен быть выровненный на 16-байтовых границах, и это было бы легче, если я могу гарантировать упорядочивание полей.
Кроме того, для невиртуальных классов адрес первого элемента также, вероятно, чтобы быть адресом структуры?
Я больше всего интересуюсь GCC и MSVS.
И 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 «совместимость» означает, что аргумент в лучшем случае становится довольно слабым.
C ++ наследует от c потребность / желание эффективно работать на многих платформах и поэтому оставляет некоторые вещи на усмотрение компилятора. Помимо требования, чтобы элементы отображались в указанном порядке, это один из них.
Но многие компиляторы поддерживают #pragma
и параметры, позволяющие установить контроль над упаковкой. См. Документацию к вашему компилятору.
Структуры последовательно размещаются в памяти. Однако способ их выравнивания в памяти зависит от операционной системы.
Для вещей, размер которых превышает 4 байта, есть разница между Windows и Linux. Linux выравнивает их, как если бы они были 4 байтами, поэтому, например, двойное (8 байтов) может начинаться с p + 4, p + 8, p + 12 и т. Д., Где p - начало структуры. В Windows двойное значение (8 байт) должно начинаться с адреса, кратного 8, поэтому p + 8, p + 16, p + 24 и т. Д.
Так устроены структуры 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», чтобы гарантировать правильную работу. Может быть, и не нужно, но это определенно сработает.
C struct
s (и C ++ POD, для совместимости) требуются по стандарту, чтобы иметь последовательную компоновку .
Единственное различие между компиляторами - это выравнивание, но, к счастью, и MSVC, и GCC поддерживают #pragma pack
.