0

I’m trying to understand how structures are aligned. According to this source, I would have expected the struct

#include<inttypes.h>
#include<stdio.h>

typedef struct {
  uint16_t a;
  uint16_t b;
  uint32_t c;
} test_struct;

int main (int argc, char const *argv[])
{
  printf("%lu\n", sizeof(test_struct));
  return 0;
}

to have a size of 12 bytes. It only takes 8 bytes in my example. As it contains an 32 bit integer I thought it should be aligned to 4 bytes, apparently that isn’t the case.

After having looked around I found this this answer which suggests than only the members themselves need to be aligned.

This totally explains the size of my struct, but how does this line up with my first source claiming “a struct instance will have the alignment of its widest scalar member”? Is that wrong or am I missing something?

Community
  • 1
  • 1
Ferio
  • 516
  • 2
  • 13
  • 5
    The two `uint16_t` types are aligned fine and occupy 4 bytes; the `uint32_t` is aligned on 4 bytes; the total should be, and is, 8 bytes. Each type has to be aligned compared with the start using its own appropriate alignment. – Jonathan Leffler Jul 24 '16 at 17:34
  • If you had changed the struct order to `a, c, b`, you'd get 12 because there would need to be 2 bytes of padding/alignment between `a` and `c` to honor `c`'s need for 4 byte alignment. – Craig Estey Jul 24 '16 at 17:39
  • 1
    The struct is aligned to 4 bytes. Why do you think it isn't? – melpomene Jul 24 '16 at 17:39
  • @melpomene: Because `a` and `b` are aligned to 2 bytes. Probably a misunderstanding on my side what "struct is aligned to x bytes means". – Ferio Jul 26 '16 at 00:59

1 Answers1

2

Both of your sources are correct.

typedef struct {
uint16_t a; // 2 bytes
uint16_t b; // 2 bytes
uint32_t c; // 4 bytes
} test_struct;

The total size of the struct is 8 bytes. To determine if padding is needed, we examine the widest scalar member (4 bytes) and check if the that number is divisible by the total size without padding.

8 % 4 == 0

Thus we don't need padding.

If we had:

typedef struct {
uint16_t a; // 2 bytes
uint16_t b; // 2 bytes
uint32_t c; // 4 bytes
uint16_t d; // 2 bytes
} test_struct;

Total size: 10 bytes

12 % 4 == 2

Padding required: 2 bytes

Total actual size: 12 bytes

Tyler
  • 740
  • 9
  • 27
  • The criterion of whether the widest member size evenly divides the sum of the sizes of the members is not a reliable indicator of whether padding is needed. If the example structure were `struct { uint16_t a; uint32_t b; uint16_t c; }`, with all scalar types involved having an alignment requirement equal to their size, then two bytes of padding would be required between `a` and `b`, and another two after `c`, for a total size of 12. It is true that the struct size must be a multiple of the strictest alignment requirement of any member, but that's not the only consideration. – John Bollinger Nov 21 '21 at 13:32