Unexpected size when a struct has a union

fatdragon Source

I am trying to verify the size of a struct. For some reasons, it's giving me a size of 18 rather than the expected 14 bytes (the union should have a max of 8 + 2 + 2 = 12 bytes). Can someone help me?

typedef struct __attribute__((__packed__)) def
{
        union {
                double x;   /* 8 bytes */
                char *y;    /* 8 bytes as for 64-bit system */
                struct {
                        struct def *array; /* 8 bytes */
                        unsigned short a;  /* 2 bytes */
                        unsigned short b;  /* 2 bytes */
                } z;
        } w;
        unsigned short v;  /* 2 bytes */
} DEF, *DEFP;

int main(int argc, char **argv) {
        printf("size of DEF = %lu\n", sizeof(DEF));
        printf("size of unsigned short = %lu\n", sizeof(unsigned short));
        printf("size of struct def * = %lu\n", sizeof(struct def *));
        printf("size of char * = %lu\n", sizeof(char *));
        printf("size of double = %lu\n", sizeof(double));
}

Here's what it displays when I run it:

$ gcc test.c && ./a.out
size of DEF = 18
size of unsigned short = 2
size of struct def * = 8
size of char * = 8
size of double = 8
cstructsizeofstructure-packing

Answers

answered 5 days ago alk #1

__attribute__((__packed__)) refers to struct def only. It does not pack the anonymous struct inside the anonymous union inside struct def.

So most likely those two members

                   unsigned short a;  /* 2 bytes */
                   unsigned short b;  /* 2 bytes */

"use" 4 but 2 bytes.


Unrelated to your question: C mandates to print size_ts using the z length modifier:

 printf("size of DEF = %zu\n", sizeof (DEF));

answered 5 days ago Art #2

Writing:

struct foo {
    struct bar {
        ...
    } x;
};

Is not different than writing:

struct bar { ... };
struct foo {
    struct bar x;
};

Why does it matter? It matters because in the second example it should be obvious why the attributes that you apply to foo don't automatically apply to bar. This means that your outer struct will be packed, but that doesn't change what the components mean.

The inner struct you have will not be packed and it's pretty obvious that if it follows the usual rules of alignment that most architectures follow its size will be a multiple of its most strictly aligned member which will be the pointer. So the size of the struct inside the union will be 16, not 12 as you assumed. Which means that the size of the union will be 16 as well.

comments powered by Disqus