I'm confused with how gcc and clang lay out structs when both padding and inheritance are involved. Here's a sample program:
#include <string.h>
#include <stdio.h>
struct A
{
void* m_a;
};
struct B: A
{
void* m_b1;
char m_b2;
};
struct B2
{
void* m_a;
void* m_b1;
char m_b2;
};
struct C: B
{
short m_c;
};
struct C2: B2
{
short m_c;
};
int main ()
{
C c;
memset (&c, 0, sizeof (C));
memset ((B*) &c, -1, sizeof (B));
printf (
"c.m_c = %d; sizeof (A) = %d sizeof (B) = %d sizeof (C) = %d\n",
c.m_c, sizeof (A), sizeof (B), sizeof (C)
);
C2 c2;
memset (&c2, 0, sizeof (C2));
memset ((B2*) &c2, -1, sizeof (B2));
printf (
"c2.m_c = %d; sizeof (A) = %d sizeof (B2) = %d sizeof (C2) = %d\n",
c2.m_c, sizeof (A), sizeof (B2), sizeof (C2)
);
return 0;
}
Output:
$ ./a.out
c.m_c = -1; sizeof (A) = 8 sizeof (B) = 24 sizeof (C) = 24
c2.m_c = 0; sizeof (A) = 8 sizeof (B2) = 24 sizeof (C2) = 32
Structs C1 and C2 are laid out differently. In C1 m_c is allocated in the back-padding of struct B1 and is therefore overwritten by the 2nd memset (); with C2 it doesn't happen.
Compilers used:
$ clang --version
Ubuntu clang version 3.3-16ubuntu1 (branches/release_33) (based on LLVM 3.3)
Target: x86_64-pc-linux-gnu
Thread model: posix
$ c++ --version
c++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
The same happens with -m32 option (sizes in the output will be different, obviously).
Both x86 and x86_64 versions of Microsoft Visual Studio 2010 C++ compiler don't have this issue (i.e. they lay out structs С1 and C2 identically)
If it's not a bug and is by design, then my questions are:
- what are the precise rules for allocating or not allocating fields of a derived struct in the back-padding (e.g. why it doesn't happen with C2?)
- is there any way to override this behaviour with switches/attributes (i.e. lay out just like MSVC does)?
Thanks in advance.
Vladimir