Home > other >  class / struct member Alignment, Data Packing under 64bits program
class / struct member Alignment, Data Packing under 64bits program

Time:01-18

class A {
    int a;
public:
    virtual ~A() {}
};

class B : public A {
    int b;
};

int main(int argc, char* argv[])
{
    cout << sizeof(B) << endl;
    return 0;
}

(Based on 64bits program), I notice the differences of the values under Visual Studio and gcc, respectively are 24 and 16. enter image description here enter image description here

By analyzing, the virtual table costs 8 bytes, int a and int b respectively is 4 bytes. So the alignment for VS is 8 but for gcc is 4.

What does cause the difference, how does the C standard say?

struct C {
    char a;
    int b;
    char c;
};

int main(int argc, char* argv[])
{
    cout << sizeof(C) << endl;
    return 0;
}

Moreover, under VS, the size of this struct is 12 that implies the alignment is 4, different from the alignment for class B under VS. enter image description here

Why?

CodePudding user response:

You will find that alignof(A) == 8 && sizeof(A) == 16 on both compilers, laid out as 8 bytes for a pointer, 4 bytes for int A::a, and 4 bytes of padding.

Since A is a base class, it is a potentially overlapping subobject of any B objects. This means that the padding can be reused.

gcc/clang (More specifically, things that follow the Itanium ABI) have to allocate int B::b into the 4 bytes of padding in the base class, so sizeof(B) is also 16 (but alignof(B) == 8 still).

MSVC (and clang compiling for Windows) follow a different ABI, which happens to not reuse the tail padding, so the layout of B looks like 8 bytes for a pointer, 4 bytes for int A::a, 4 bytes of padding (inherited from A), 4 bytes for int B::b, and 4 more bytes of padding.


As for your last questions, typically vtables are implemented as a pointer stored at the front of each object. This pointer will usually have the size an alignment requirement of 8 on a 64 bit platform. C would be comparable if it looked like:

struct C {
    void* p;
    char a;
    // 3 bytes padding
    int b;
    char c;
    // 7 bytes padding to alignment of 8
};

static_assert(sizeof(C) == 24 && alignof(C) == 8);

CodePudding user response:

With the other's help, I finally figure it out.

alignof(B) under VS and GCC are same which is 8.

1. Why sizeof(B) are different?

Because they store the virtual function pointer (vptr) at different places, for VS at beginning and for GCC at the end. Something like this,

//B for VS

class B{
class A{
void* vptr;
int a;
};
int b;};
//B for GCC
class B{
int a;
int b;
void* vptr;
};

For VS, sizeof(B) = sizeof(vptr) (sizeof(int a) padding to 8) (sizeof(int b) padding to 8) = 24.

For GCC, sizeof(B) = (sizeof(int a) sizeof(int b) padding to 8) sizeof(vptr) = 16.

2. Why alignof(C) is 4?

Because there is virtual function in struct C. If you add virutal ~C(){} for C, alignof(C) would be 8 either.

  • Related