Thursday, May 28, 2009

Another Note on Empty Structs

I mentioned this C++ Standard Violation by MSVC++ in my last post on empty structs:

- There is no padding (other than for alignment) between the last base class and the first class member or vft-pointer(s). *** NOTE: this is an over-aggressive empty-base-optimization that can break the C++ standard.

Let me explain:

The standard on empty struct inheritance specifies that separate structs of the same type should yield unique addresses. In the following code, the two addresses printed should be different in a standards compliant compiler (Intel or GCC). MSVC++ ends up printing the same address twice.

class a { public: void awork() {} };
class b : public a { public: int bdata; };
class c : public a { public: b cdata; };
c test;
a *pca=&(test);
a *pcb=&(test.cdata);
printf("Offset of c::a %d\n",size_t(pca));
printf("Offset of c.b::a %d\n",size_t(pcb));

Friday, May 1, 2009

Empty Struct / Class & Empty Base Rules for MSVC++ and GCC

I now GROK empty class (and empty base optimizations) fully on MSVC and GCC.

----------------------------------------------------------

GCC C++ follows these rules:

- class EmptyBase {}; --> sizeof(EmptyBase) == 1

- Any number of empty-bases will map to 0 in the struct offset as long as all are unique types (including parenting).

- Non empty-base parents are simply in the order declared with only padding for alignment.

- If the first member of a derived class that immediately follows empty-bases does not derive from any of those bases, it is allowed to start at the first properly aligned offset for that member that is greater-than-or-equal-to the empty-base address -- this may be the same address as the empty-bases.

- If the first member of a derived class that immediately follows empty-bases does derive from any of those bases, it will start at the first properly aligned offset for that member that is greater-than the empty-base address -- this is never the same address as the empty-bases.

- Members that are empty-classes take at least one byte of storage in the containing class.

----------------------------------------------------------

MSVC++ follows these rules:

- class EmptyBase {}; --> sizeof(EmptyBase) == 1

- The only way an empty-base class (or class derived from an empty-base) will start at offset 0 (zero) is if it is the first base class.

- A Non-empty-base class will start at the next valid alignment offset for the base class.

- All empty-base classes will appear to have zero effective storage in the derived class and do not affect the current offset unless followed by another empty-base class (or class derived from an empty-base) in which case you should see the following rule.

- An empty-base class (or class derived from an empty-base) that follows an empty-base class (or class derived from an empty-base) will add 1 to the current offset position before padding to the proper alignment for the class.

- There is no padding (other than for alignment) between the last base class and the first class member or vft-pointer(s). *** NOTE: this is an over-aggressive empty-base-optimization that can break the C++ standard.

- Members that are empty-classes take at least one byte of storage in the containing class.