Structure size with union and bitfields

I am trying to calculate the size in bytes of this structure and ask a couple of questions

struct stc {
    int a;
    int b;
    char c;
    union stc2 {
        long a0;
        int a1;
        int a2;
    };
    char arr[10];
    int z:2;
};

      

I check the size this way:

int main(void) {
    printf("%zu\n", sizeof(struct stc));
}

      

and compile with:

gcc -std=c99 -m32 -Wall -Wextra test.c

This is gcc 4.9 and I am on a 64 bit machine but want to try with 32 bit values ​​-m32 first. Now the result 20

, but I don't know why it is. This is how I calculate.

struct stc {     
    int a;        // +4 = 4
    int b;        // +4 = 8
    char c;       // +1 but next is long, so +4 (alignment) = 12
    union stc2 {
        long a0;  // +4 = 16
        int a1;
        int a2;
    };
    char arr[10]; // +8 (for arr[8]) and 2 bits left = 24 (or 28)
    int z:2;      // +4 = 28 (or 32) 
                  // I'm not sure how it'll work with 2 bits left from char array and
                  // 2 bits from int, so that why I count 2 different values. 
};

      

It was weird, so I tried to figure it out and I know that this union looks like a size of 0.

struct stc {
    union stc2 {
        long a0;
        int a1;
        int a2;
    };

      

sizeof(struct stc) == 0

... I think this is due to compiler optimizations? If so, how do I disable it? If not, why not? Another question, of course, is how to correctly calculate the size of this structure (with or without optimization) and why the size of this simple structure:

struct stc {
    char arr[10];
};

      

is not 10, not 12. I thought every value is aligned with 4,8,12,16,20 and so on, unless you tell the compiler not to align the values.

+3


source to share


1 answer


So you have a lot of questions here. I'll answer some as I go:

sizeof struct is zero?

You provided the code:

struct stc {
    union stc2 {
        long a0;
        int a1;
        int a2;
    };
};

      

Please note that you did not specify variables inside the structure. You should probably do the following, which will probably be the same size as sizeof(long)

.

struct stc {
    union stc2 {
        long a0;
        int a1;
        int a2;
    } x;
};

      

Beatle mockups

So, let's try to figure out where it comes from 20

. First, rewrite the type without union

, which does nothing (see the previous heading).

Also note that bitfield structures are not required , which must be allocated in memory in the same way as normal types. But let them guess.

struct stc {
    int a;        // Offset 0,  Size 4
    int b;        // Offset 4,  Size 4
    char c;       // Offset 8,  Size 1
    char arr[10]; // Offset 9,  Size 10
    int z:2;      // Offset 19, Size 1-ish
};

      

So it seems to fit perfectly.



sizeof was not rounded to 12?

struct stc {
    char arr[10];
};

      

Thus, each type has a size and alignment requirement. For char

, they are both equal to 1. For, uint32_t

they are usually equal to 4. But depending on the architecture, the alignment may be different.

So in this case, the maximum alignment requirements for any structure element stc

are 1. So, the alignment requirements for the entire structure are still 1

, though size 10

.

Generally speaking, you want to add any padding for the size so that the declaration will struct stc x[2]

align all elements.

Recommendations

So, there are a few things you can do here to find out what your compiler is doing.

  • When posting questions about memory layout on Stack Overflow, it is very helpful to use the types defined in stdint.h

    . These include types such as int32_t

    and int16_t

    . This is better because there is no confusion about what size a is long

    .

  • You can use the offsetof tool to determine where the compiler is placing the elements. You can read more on how to use it here .

Filling can occur though:

Here's a pretty basic example of a structure with a nice bit of padding that the compiler would have to insert.

struct x {
    uint64_t x; // Offset 0,  Size 8
    char     y; // Offset 8,  Size 1
                // Offset 9,  Size 1 (Padding)
    uint16_t z; // Offset 10, Size 2
                // Offset 12, Size 4 (Padding)
}; 

      

+5


source







All Articles