Consider these two cases :
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);
Is it always safe to do this ?
I want to know if standard specifies any order of storage among -
- The elements inside a C structure.
- Data members inside an object of a C++ class.
C99 and C++ differ a bit on this.
The C99 standard guarantees that the fields of a struct will be laid out in memory in the order they are declared, and that the fields of two identical structs will have the same offsets. See this question for the relevant sections of the C99 standard. To summarize: the offset of the first field is specified to be zero, but the offsets after that are not specified by the standard. This is to allow C compilers to adjust the offsets of each field so the field will satisfy any memory alignment requirements of the architecture. Because this is implementation-dependent, C provides a standard way to determine the offset of each field using the offsetof
macro.
C++ offers this guarantee only for Plain old data (POD). C++ classes that are not plain old data cannot be treated like this. The standard gives the C++ compiler quite a bit of freedom in how it organizes a class when the class uses multiple inheritance, has non-public fields or members, or contains virtual members.
What this means for your examples:
dataType1 firstMemberInsideStruct = (dataType1)(*instance2);
This line is okay only if dataType1, dataType2, and dataType3 are plain old data. If any of them are not, then the customType struct may not have a trivial constructor (or destructor) and this assumption may not hold.
dataType1 firstMemberInTheObject = (dataType1) (*pointerToAnObject);
This line is not safe regardless of whether dataType1
, dataType2
, and dataType3
are POD, because the CustomType
class has private instance variables. This makes it not a POD class, and so you cannot assume that its first instance variable will be ordered in a particular way.
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 ]
It's not always safe to do so. If the classes have virtual
methods, it most definitely is not. Data members are guaranteed to appear in the same order for the same access level chunk, but these groups can be reordered.
In order to be safe with these type of casts, you should provide a conversion constructor or a cast operator, and not rely on implementation details.
Typically in a C struct members are stored in the order that they are declared. However the elements must be aligned properly. Wikipedia has a good example of how this works.
I will re-iterate here:
If you have the following struct
struct MixedData
{
char Data1;
short Data2;
int Data3;
char Data4;
};
padding will be inserted in between differing data types in order to assure the proper byte-alignment. char
s are 1-byte aligned, short
s are 2-byte aligned, int
s are 4-byte aligned, etc.
Thus to make Data2
2-byte aligned, there will be a 1-byte padding inserted between Data1
and Data2
.
It is also worth mentioning that there are mechanisms that can change the packing alignment. See #pragma pack.