Do Class/Struct Members Always Get Created in Memory in the Order They Were Declared

Do class/struct members always get created in memory in the order they were declared?

C99 §6.7.2.1 clause 13 states:

Within a structure object, the
non-bit-field members and the units in
which bit-fields reside have addresses
that increase in the order in which
they are declared.

and goes on to say a bit more about padding and addresses. The C89 equivalent section is §6.5.2.1.

C++ is a bit more complicated. In the 1998 and 2003 standards, there is §9.2 clause 12 (clause 15 in C++11):

Nonstatic data members of a
(non-union) class declared without an
intervening access-specifier are
allocated so that later members have
higher addresses within a class
object. The order of allocation of
nonstatic data members separated by an
access-specifier is unspecified
(11.1). 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).

Does the order of members in a struct matter?

The order of fields in a struct does matter - the compiler is not allowed to reorder fields, so the size of the struct may change as the result of adding some padding.

In this case, however, you are defining a so-called flexible member, an array the size of which you can change. The rules for flexible members are that

  • There may never be more than one such member,
  • If present, the flexible member must be the last one in the struct, and
  • The struct must have at least one member in addition to the flexible one.

Take a look at this Q&A for a small illustration on using flexible structure members.

Order of fields in C/C++ structs

The general rules about field layout in C are:

  1. The address of the first member is the same as the address of the struct itself. That is, the offsetof of the member field is 0.
  2. The addresses of the members always increase in declaration order. That is, the offsetof of the n-th field is lower than that of the (n+1)-th member.

In C++, of course, that is only true if it is a standard layout type, that is roughly, a class or struct with no public/private/protected mixed members, no virtual functions and no members inherited from other classes.

Member fields, order of construction

Yes, the order of construction is always guaranteed. It is not, however, guaranteed to be the same as the order in which the objects appear in the initializer list.

Member variables are constructed in the order in which they are declared in the body of the class. For example:

struct A { };
struct B { };

struct S {
A a;
B b;

S() : b(), a() { }
};

a is constructed first, then b. The order in which member variables appear in the initializer list is irrelevant.

Can we scramble the declaration order in C or C++?

Run-time foxing is the best way, then you only have to release a single version. Where a struct has several fields of the same type, you can use an array instead. Step 1. Instead of a structure with three int fields use an array

#define foo 0
#define bar 1
#define zee 2

struct abc {
int scramble [3];
};

...
value = abc.scramble[bar];

Step 2, now use an indexing array which is randomised every time the program is run.

int abcindex [3];               // index lookup 
int abcpool [3]; // index pool for randomise

for (i=0; i<3; i++) // initialise index pool
abcpool[i] = i;

srand (time(NULL));
for (i=0; i<3; i++) { // initialise lookup array
j = rand()%(3-i);
abcindex[i] = abcpool[j]; // allocate random index from pool
abcpool[j] = abcpool[2-i]; // remove index from pool
}

value = abc.scramble[abcindex[bar]];

Another way to try to fox a hacker is to include subterfuge variables that behave as if they have something to do with it but make the program exit if tampered with. Lastly you can keep some kind of checksum or encrypted copy of key variables, to check if they have been tampered with.

Members declaration order in a class if they depend on eachother, optimal solution

As the order of initialisation is dependent on the order they are defined in your class, the member order is ignored: C++: Initialization Order of Class Data Members.

So I would just move the integer and string above MyOb1 and MyOb2, also @Matt McNabb also pointed out that you should use the params passed in your constructor in the initialisation of your MyOb1/2 objects to avoid ambiguity (a sensible suggestion):

class MyClass
{
private:
int i;
std::string str;
MyOb1 Obj1;
MyOb2 Obj2;

public:
MyClass(int iIn, const std::string& strIn)
: i(iIn), // here
str(strIn),
Obj1(iIn),
Obj2(iIn, strIn) {}
}

To quote from the standard section 12.6.2 (the latest draft has this on page 266):

5 Initialization shall proceed in the following order:

— First, and only for the constructor of the most derived class as
described below, virtual base classes shall be initialized in the
order they appear on a depth-first left-to-right traversal of the
directed acyclic graph of base classes, where “left-to-right” is the
order of appearance of the base class names in the derived class
base-specifier-list.

— Then, direct base classes shall be initialized in declaration order
as they appear in the base-specifier-list (regardless of the order of
the mem-initializers).

— Then, nonstatic data members shall be initialized in the order they
were declared in the class definition (again regardless of the order
of the mem-initializers).

— Finally, the body of the constructor is executed. [Note: the
declaration order is mandated to ensure that base and member
subobjects are destroyed in the reverse order of initialization. ]



Related Topics



Leave a reply



Submit