sizeof union larger than expected. how does type a

2019-01-28 06:27发布

问题:

#include <stdio.h>

union u1 {
    struct {
        int *i;
    } s1;
    struct {
        int i, j;
    } s2;
};

union u2 {
    struct {
        int *i, j;
    } s1;
    struct {
        int i, j;
    } s2;
};

int main(void) {
    printf("        size of int: %zu\n", sizeof(int));
    printf("size of int pointer: %zu\n", sizeof(int *));
    printf("   size of union u1: %zu\n", sizeof(union u1));
    printf("   size of union u2: %zu\n", sizeof(union u2));
    return 0;
}

Results in:

$ gcc -O -Wall -Wextra -pedantic -std=c99 -o test test.c
$ ./test
        size of int: 4
size of int pointer: 8
   size of union u1: 8
   size of union u2: 16

Why does adding an integer of 4 bytes to nested struct s1 of union u2 increase the size of the union as a whole by 8 bytes?

回答1:

The struct u2.s2 is 16 bytes because of alignment constraints. The compiler is guaranteeing that if you make an array of such structs, each pointer will be aligned on an 8-byte boundary. The field *i takes 8 bytes, then j takes 4 bytes, and the compiler inserts 4 bytes of padding. Because the struct is 16 bytes, the union containing it is also 16 bytes.



回答2:

That's because the compiler needs to keep the entire struct (as well as the union) aligned to 8 bytes - due to the fact that you have a pointer inside. (which is 8-bytes in your case)

So even though you add only 4 bytes with the extra int, struct-alignment forces everything to be aligned to 8 bytes - hence the +8 to bring the total size to 16 bytes.

The result of this is that:

struct {
    int *i, j;
} s1;

has a size of 16 bytes. Since a union must be at least as large as the largest element, it is also forced up to 16.

http://en.wikipedia.org/wiki/Data_structure_alignment



回答3:

Since a pointer is 8 bytes on your platform, it most probably also requires an alignment of 8 bytes. So when adding another 4 bytes, the struct cannot just have a size of 12 bytes, in which case the individual elements of say an array of u2s would not be properly aligned at 8 byte boundaries, which is neccessary for the pointer member. So you need to increase its size to the next multiple of 8, which is 16. The additional 4 bytes are just unused/undefined.