6

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 -

  1. The elements inside a C structure.
  2. Data members inside an object of a C++ class.
Amit Tomar
  • 4,800
  • 6
  • 50
  • 83
  • Definitely not if the class is polymorphic. But I'm not sure on the technical details of when exactly it's safe to do. – Mysticial Jul 05 '12 at 07:54
  • in c++ classes and structs are basically the same besides the keyword. The Dataorder is as you descrtibed, but if you want to be 100% sure you can use inheritance, if you just need to access the first object. Btw why don't you create direct pointers to the members then you can do something like `*(classInstancepointer->memberpointer)` (approximately has been a while) to access the data, by exchanging the instance pointer you can access the data in different Instances. – ted Jul 05 '12 at 07:57
  • I don't think it is a generally safe thing to do in C++: you have to take base (derived from) classes into consideration. The order of the member variables, is guaranteed to match the source. It is not very different for C and C++: C++ classes can have parent classes and a table of virtual methods, which C does not have. This makes the result of "firstMemberInObject" somewhat harder to read from the source. Besides, alignment of the fields can add come padding before the first field. – fork0 Jul 05 '12 at 08:04
  • @ted: &instance.member, which is completely safe thing to do – fork0 Jul 05 '12 at 08:05
  • @fork0 `&instance.member` is to set up the pointer, yezx i forgot to put that. But I think I can racall something like `auto p=&class::member` and `auto inst=&class()` to be used ass member and instance pointer in the code I mentioned above. In your case it looks like you are already getting a bound object pointer which i think difers slightly from the desired result. – ted Jul 05 '12 at 09:24
  • @ted: this `&class::member` works only for static elements of a class. That'd be static variables and methods (you can get an address of a method by `&` operator). The other construction is actually an error: you get an address to a temporary object. Still can have its uses though: as an argument to a function: `func(&class())`. Using a reference in this argument will make it shorter. – fork0 Jul 05 '12 at 11:27

4 Answers4

7

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.

Community
  • 1
  • 1
sfstewman
  • 5,589
  • 1
  • 19
  • 26
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 ]

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
ForEveR
  • 55,233
  • 2
  • 119
  • 133
1

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.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
0

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. chars are 1-byte aligned, shorts are 2-byte aligned, ints 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.

tskuzzy
  • 35,812
  • 14
  • 73
  • 140