Search code examples
cstructsizeof

Why sizeof shows 8 bytes?


Why sizeof shows 8 byte in this code?

int has 4 bytes

char has 1 byte

Why sizeof don't show 5 bytes?

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    struct test
    {
        int num;
        char ch;
    };

    printf("%lu", sizeof(struct test));
    return 0;
}

I thought that sizeof showed 5 but it showed 8 bytes


Solution

  • Observe:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void)
    {
        struct test
        {
            int num;
            char ch;
        };
    
        struct test2
        {
            int num;
            char ch;
        } __attribute__((packed));
    
        printf("%d\n", (int)sizeof(struct test));
        printf("%d\n", (int)sizeof(struct test2));
        return 0;
    }
    
    stieber@gatekeeper:~ $ gcc Test.c && ./a.out
    8
    5
    

    The first version uses "padding", so things like allocating memory for an array of 10 test structures by just doing 10*sizeof(test) will still give an efficient memory layout.

    Unaligned access, like accessing a 4-byte integer at a memory location that's not on a 4-byte boundary is less efficient, and on some platforms, even causes a crash.

    Note that the attribute is a gcc extension. It's not too uncommon for compilers to offer it, but there's no standard so other compilers need something else.

    As a side note, this is also why ordering of structure members can be an issue:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void)
    {
        struct test1
        {
            char ch;
            int num;
            char ch2;
        };
    
        struct test2
        {
            int num;
            char ch;
            char ch2;
        };
    
        struct test3
        {
            char ch;
            char ch2;
            int num;
        };
    
        printf("%d\n", (int)sizeof(struct test1));
        printf("%d\n", (int)sizeof(struct test2));
        printf("%d\n", (int)sizeof(struct test3));
        return 0;
    
    }
    
    stieber@gatekeeper:~ $ gcc Test.c && ./a.out
    12
    8
    8
    

    As you can see, the first one takes more memory than the second one, even though the actual data is "the same". This is because the compiler has to move the int member to a 4-byte boundary, so it inserts 3 padding bytes after the char (it always works under the assumption that the struct itself is placed at a location that satisfies all aligment requirements).

    If we put both 'char' members together, the compiler doesn't need to add more padding since chars have no specific alignment requirements to be efficient.