Tail padding, more differences

michaelw at ca.ibm.com michaelw at ca.ibm.com
Mon Aug 26 23:07:28 UTC 2002


We have observed a possible difference in tail padding for bitfields in
father and grandfather cases when it does not overflow the byte boundary.
For the following testcase, every other offset seems to start a new byte
boundary.

#include <stdio.h>
#include <string.h>
//void operator delete(void *) throw() {}
struct A { virtual ~A() {}; int a : 2; };
struct B0 : A { int b0 :3; };
struct B1 : B0 { int b1 :2; };
struct B2 : B1 { int b2 :3; };
struct B3 : B2 { int b3 :1; };
void hexdumpbit(const char * comment, const void * a, int size, int
delimit) {
        printf("--%s--- dumping %d bytes-----\n", comment, size);
        const char * p = (const char *) a;
        for (int i=0; i< size; ++i ) {
                printf("%s", (0 != (p[i]&0x80))? "1":"0");
                printf("%s", (0 != (p[i]&0x40))? "1":"0");
                printf("%s", (0 != (p[i]&0x20))? "1":"0");
                printf("%s", (0 != (p[i]&0x10))? "1":"0");
                printf("%s", (0 != (p[i]&0x08))? "1":"0");
                printf("%s", (0 != (p[i]&0x04))? "1":"0");
                printf("%s", (0 != (p[i]&0x02))? "1":"0");
               printf("%s ", (0 != (p[i]&0x01))? "1":"0");
                if (0 == (i+1)%delimit) printf("\n");
        }
        printf("\n");
}
int main() {
  printf("sizeof(A) == %lu; sizeof(B0) == %lu, sizeof(B1) == %lu,
sizeof(B2) == %lu, sizeof(b3) == %lu \n"
        , (unsigned long)sizeof(A)
        , (unsigned long)sizeof(B0)
        , (unsigned long)sizeof(B1)
        , (unsigned long)sizeof(B2)
        , (unsigned long)sizeof(B3)
        );
  B0 bb;
  memset(&bb,0, sizeof bb); bb.a=3; hexdumpbit("bb.a", &bb, sizeof bb, 8);
  memset(&bb,0, sizeof bb); bb.b0=7; hexdumpbit("bb.b0", &bb, sizeof bb,
8);

  B1 b1;
  memset(&b1,0, sizeof b1); b1.a=3; hexdumpbit("b1.a", &b1, sizeof b1, 8);
  memset(&b1,0, sizeof b1); b1.b0=7; hexdumpbit("b1.b0", &b1, sizeof b1,
8);
  memset(&b1,0, sizeof b1); b1.b1=3; hexdumpbit("b1.b1", &b1, sizeof b1,
8);

  B2 b2;
  memset(&b2,0, sizeof b2); b2.a=3; hexdumpbit("b2.a", &b2, sizeof b2, 8);
  memset(&b2,0, sizeof b2); b2.b0=7; hexdumpbit("b2.b0", &b2, sizeof b2,
8);
  memset(&b2,0, sizeof b2); b2.b1=3; hexdumpbit("b2.b1", &b2, sizeof b2,
8);
  memset(&b2,0, sizeof b2); b2.b2=7; hexdumpbit("b2.b2", &b2, sizeof b2,
8);

  B3 b3;
  memset(&b3,0, sizeof b3); b3.a=3; hexdumpbit("b3.a", &b3, sizeof b3, 8);
  memset(&b3,0, sizeof b3); b3.b0=7; hexdumpbit("b3.b0", &b3, sizeof b3,
8);
  memset(&b3,0, sizeof b3); b3.b1=3; hexdumpbit("b3.b1", &b3, sizeof b3,
8);
  memset(&b3,0, sizeof b3); b3.b2=7; hexdumpbit("b3.b2", &b3, sizeof b3,
8);
  memset(&b3,0, sizeof b3); b3.b3=1; hexdumpbit("b3.b3", &b3, sizeof b3,
8);
  return 0;
}


gcc 3.2 prints:

sizeof(A) == 8; sizeof(B0) == 8, sizeof(B1) == 8, sizeof(B2) == 8,
sizeof(b3) == 8
--bb.a--- dumping 8 bytes-----
00000000 00000000 00000000 00000000 11000000 00000000 00000000 00000000

--bb.b0--- dumping 8 bytes-----
00000000 00000000 00000000 00000000 00111000 00000000 00000000 00000000

--b1.a--- dumping 8 bytes-----
00000000 00000000 00000000 00000000 11000000 00000000 00000000 00000000

--b1.b0--- dumping 8 bytes-----
00000000 00000000 00000000 00000000 00111000 00000000 00000000 00000000

--b1.b1--- dumping 8 bytes-----
00000000 00000000 00000000 00000000 00000000 11000000 00000000 00000000

--b2.a--- dumping 8 bytes-----
00000000 00000000 00000000 00000000 11000000 00000000 00000000 00000000

--b2.b0--- dumping 8 bytes-----
00000000 00000000 00000000 00000000 00111000 00000000 00000000 00000000

--b2.b1--- dumping 8 bytes-----
00000000 00000000 00000000 00000000 00000000 11000000 00000000 00000000

--b2.b2--- dumping 8 bytes-----
00000000 00000000 00000000 00000000 00000000 00111000 00000000 00000000

--b3.a--- dumping 8 bytes-----
00000000 00000000 00000000 00000000 11000000 00000000 00000000 00000000

--b3.b0--- dumping 8 bytes-----
00000000 00000000 00000000 00000000 00111000 00000000 00000000 00000000

--b3.b1--- dumping 8 bytes-----
00000000 00000000 00000000 00000000 00000000 11000000 00000000 00000000

--b3.b2--- dumping 8 bytes-----
00000000 00000000 00000000 00000000 00000000 00111000 00000000 00000000

--b3.b3--- dumping 8 bytes-----
00000000 00000000 00000000 00000000 00000000 00000000 10000000 00000000

(results from gcc 3.2 32 bit linux-ppc big-endian)

It seems that b3.b1 and b3.b3 starts a new byte boundary because of b3.a
and b3.b1 respectively. If b3.a overflows the byte boundary, then b3.b1
would pack tightly afterwards.


Our question is:
We think this is inconsistent, is this a possible bug in gcc?


Michael Wong
VisualAge C++ Compiler kernel Development
IBM Canada Ltd., C2/KD2/8200/MKM
8200 Warden Avenue
Markham, Ontario  L6G 1C7
W:905-413-3283 F:905-413-4839




More information about the cxx-abi-dev mailing list