2012-07-05 2 views
3

Рассмотрим эти два случая:Порядок хранения внутри структуры/объекта

struct customType 
{ 
    dataType1 var1; 
    dataType2 var2; 
    dataType3 var3; 
} ; 

customType instance1; 
// Assume var1, var2 and var3 were initialized to some valid values. 

customType * instance2 = &instance1;  
dataType1 firstMemberInsideStruct = (dataType1)(*instance2); 

class CustomType 
{ 
    public: 
     dataType1 member1; 
     dataType2 member2; 

     retrunType1 memberFunction1(); 

    private: 
     dataType3 member3; 
     dataType4 member4; 

     retrunType2 memberFunction2(); 
}; 

customType object; 
// Assume member1, member2, member3 and member4 were initialized to some valid values. 

customType *pointerToAnObject = &object ; 
dataType1 firstMemberInTheObject = (dataType1) (*pointerToAnObject); 

Это всегда безопасно это сделать?

Я хочу знать, если стандарт определяет любой порядок хранения среди -

  1. элементов внутри структуры C.
  2. Элементы данных внутри объекта класса C++.
+0

Определенно нет, если класс является полиморфным. Но я не уверен в технических деталях, когда это безопасно. – Mysticial

+0

в C++ классы и структуры в основном одинаковы, кроме ключевого слова. Dataorder, как вы описали, но если вы хотите быть на 100% уверенным, вы можете использовать наследование, если вам просто нужно получить доступ к первому объекту. Кстати, почему бы вам не создать прямые указатели на элементы, тогда вы можете сделать что-то вроде '* (classInstancepointer-> memberpointer)' (примерно какое-то время) для доступа к данным, путем обмена указателем экземпляра вы можете получить доступ к данным в разные экземпляры. – ted

+0

Я не думаю, что это вообще безопасно делать в C++: вы должны учитывать базовые (производные от) классы. Порядок переменных-членов гарантированно соответствует источнику. Это не очень отличается для C и C++: классы C++ могут иметь родительские классы и таблицу виртуальных методов, которых у C нет. Это делает результат «firstMemberInObject» несколько сложнее для чтения из источника. Кроме того, выравнивание полей может добавлять заполнение перед первым полем. – fork0

ответ

4

С99 и C++, немного отличаются от этого.

Стандарт C99 гарантирует, что поля структуры будут выложены в памяти в том порядке, в котором они объявлены, и что поля двух идентичных структур будут иметь одинаковые смещения. См. this question для соответствующих разделов стандарта C99. Подводя итог: смещение первого поля указано равным нулю, но смещения после этого не определяются стандартом.Это позволяет компиляторам C корректировать смещения каждого поля, чтобы поле удовлетворяло любым требованиям к выравниванию памяти в архитектуре. Поскольку это зависит от реализации, C предоставляет стандартный способ определения смещения каждого поля с использованием макроса offsetof.

C++ предлагает эту гарантию только для Plain old data (POD). Классы C++, которые не являются простыми старыми данными, нельзя рассматривать так. Стандарт дает компилятору C++ довольно немного свободы в том, как он организует класс, когда класс использует множественное наследование, имеет непубличные поля или члены или содержит виртуальных членов.

Что это означает для ваших примеров:

dataType1 firstMemberInsideStruct = (dataType1)(*instance2); 

Эта линия хорошо только если dataType1, dataType2 и dataType3 являются простые старые данные. Если какой-либо из них нет, то структура customType может не иметь тривиального конструктора (или деструктора), и это предположение может не выполняться.

dataType1 firstMemberInTheObject = (dataType1) (*pointerToAnObject); 

Эта линия не является безопасным, независимо от того, dataType1, dataType2 и dataType3 являются POD, потому что CustomType класс имеет частные переменные экземпляра. Это делает не классом POD, и поэтому вы не можете предположить, что его первая переменная экземпляра будет упорядочена определенным образом.

0

Обычно в элементе C-структуры хранятся в том порядке, в котором они объявлены. Однако элементы должны быть правильно выровнены. В Википедии есть хороший пример how this works.

я вновь перебирать здесь:

Если у вас есть следующая структура

struct MixedData 
{ 
    char Data1; 
    short Data2; 
    int Data3; 
    char Data4; 
}; 

обивка будет вставлена ​​между различными типами данных в целях обеспечения надлежащего байтового выравнивания. char ы являются 1-байтовое выровнены, short с собой 2-байтовое выровнены, int с являются 4-байтовый выровнены и т.д.

Таким образом, чтобы сделать Data2 2-байтовое выровнены, будет 1-байтовое обивка вставляется между Data1 и Data2.

Следует также отметить, что существуют механизмы, которые могут изменить выравнивание упаковки. См. #pragma pack.

+0

Первое утверждение неверно в случае чередования полей с закрытым доступом. –

+0

C не имеет такого механизма. Извините, возможно, я должен был сказать, обычно, в C. Я не имею права ничего говорить о C++: P – tskuzzy

1

Это не всегда безопасно. Если у классов есть методы virtual, это определенно не так. Элементы данных гарантированно появятся в том же порядке для одного и того же уровня доступа, но эти группы могут быть переупорядочены.

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

6

9.0.7

A standard-layout class is a class that: — has no non-static data members of type non-standard-layout class (or array of such types) or reference, — has no virtual functions (10.3) and no virtual base classes (10.1), — has the same access control (Clause 11) for all non-static data members, — has no non-standard-layout base classes, — either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and — has no base classes of the same type as the first non-static data member.108

9.2.14

Nonstatic data members of a (non-union) class with the same access control (Clause 11) are allocated so that later members have higher addresses within a class object. The order of allocation of non-static data members with different access control is unspecified (11). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).

9.2.20

A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. — end note ]

+1

+1 для копания стандарта. –

Смежные вопросы