Всегда ли члены класса/структуры создаются в памяти в том порядке, в котором они были объявлены?

Это вопрос, возникший в результате ответа Роба Уокера здесь.

Предположим, я объявляю класс/структуру следующим образом:

struct
{ 
    char A;
    int B;
    char C;
    int D;
};

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

Это приводит к моему следующему вопросу. Если приведенный выше пример вызывает проблемы с выравниванием памяти, почему компилятор не может просто неявно превратить это во что-то вроде этого:

struct
{ 
    char A;
    char C;
    int B;
    int D;
};

(В первую очередь я спрашиваю о С++, но мне также было бы интересно услышать ответ C)

похожие темы


person Jason Baker    schedule 11.11.2008    source источник


Ответы (6)


C99 §6.7.2.1 пункт 13 гласит:

Внутри структурного объекта члены, не являющиеся битовыми полями, и единицы, в которых находятся битовые поля, имеют адреса, возрастающие в порядке их объявления.

и продолжает говорить немного больше о заполнении и адресах. Эквивалентный раздел C89 — §6.5.2.1.

С++ немного сложнее. В стандартах 1998 и 2003 годов есть пункт 12 §9.2 (пункт 15 в С++ 11):

Нестатические члены данных (не объединенного) класса, объявленного без промежуточного спецификатора доступа, выделяются таким образом, что более поздние члены имеют более высокие адреса в объекте класса. Порядок размещения нестатических элементов данных, разделенных спецификатором доступа, не определен (11.1). Требования выравнивания реализации могут привести к тому, что два соседних элемента не будут выделены сразу друг за другом; так же как и требования к пространству для управления виртуальными функциями (10.3) и виртуальными базовыми классами (10.1).

person aib    schedule 11.11.2008
comment
Этот ответ прибивает его. Единственное предостережение в том, что не все компиляторы следуют стандарту. Компиляторы, которые следуют стандарту, не обязательно следуют ему на всех уровнях оптимизации. - person Stephen Curial; 29.09.2009
comment
/ЧЕРТ/. Я не знал об этом исключении спецификатора доступа - к счастью, я уверен, что у меня нет кода, зависящего от него. - person Simon Buchan; 05.07.2010
comment
C++11: теперь §9.2 пункт 15: формулировка абзаца не изменилась. - person Andreas Florath; 16.01.2013
comment
Означают ли члены стандарта C, не являющиеся битовыми полями, что компилятору разрешено переупорядочивать именованные битовые поля? - person gsingh2011; 28.05.2013
comment
Я думаю, это означает, что битовые поля могут быть переупорядочены, но только между собой, то есть те, которые используют одну и ту же переменную. - person aib; 12.10.2013

Элементы данных располагаются в объявленном порядке. Компилятор может свободно чередовать заполнение, чтобы организовать выравнивание памяти, которое ему нравится (и вы обнаружите, что многие компиляторы имеют множество опций спецификации выравнивания — полезно, если смешиваются биты, скомпилированные разными программами).

См. также Почему GCC не оптимизирует структуры?.


Похоже, что этот ответ несколько устарел для С++. Вы узнаете что-то каждый день. Спасибо, аиб, Неманья.

person dmckee --- ex-moderator kitten    schedule 11.11.2008
comment
Спасибо за ссылку. Добавлю как родственную тему. - person Jason Baker; 11.11.2008

Я не могу говорить за C++, но в C порядок в памяти гарантированно будет таким же, как и в структуре.

person Chris Young    schedule 11.11.2008

В основном вы можете рассчитывать на это только для классов с стандартный макет. Строго говоря, стандартный макет — это вещь C++0x, но на самом деле это просто стандартизация существующей практики.

person Nemanja Trifunovic    schedule 11.11.2008

Помимо заполнения для выравнивания, никакая оптимизация структуры не разрешена ни одним компилятором (о котором я знаю) для C или C++. Я не могу говорить о классах С++, так как они могут быть совершенно другим зверем.

Предположим, что ваша программа взаимодействует с системным/библиотечным кодом в Windows, но вы хотите использовать GCC. Вам нужно будет убедиться, что GCC использует идентичный алгоритм оптимизации макета, чтобы все ваши структуры были правильно упакованы, прежде чем отправлять их в код, скомпилированный MS.

person HUAGHAGUAH    schedule 11.11.2008
comment
Действительно? Мне всегда говорили, что структуры и классы — это одно и то же, за исключением того, что структуры по умолчанию имеют открытый доступ. Или это предмет отдельного вопроса? - person Jason Baker; 11.11.2008
comment
Классы C++ ничем не отличаются от структур C++. Единственная разница заключается в том, что структуры по умолчанию используют "public" для членов или наследования, а классы используют "private". - person jalf; 11.11.2008
comment
@HUAGHAGUAH - Надеюсь, вы не возражаете, я немного подправил ваш пост. Мне нравится ваш пост, и я не хочу, чтобы кто-то проголосовал за него из-за того, что часть о классах С++ - это совсем другой зверь. :-) - person Jason Baker; 11.11.2008

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

Перефразируя, если у вас есть структура на C, которая выглядит примерно так:

struct foo{};

и создать подкласс в С++ (используя отдельный модуль компиляции):

extern "C" foo;
struct bar: public foo{};

Тогда выравнивание памяти не обязательно будет одинаковым по причинам aib упоминается (даже среди компиляторов одного и того же поставщика).

person Jason Baker    schedule 11.11.2008