0

Similar questions were asked, but answers didn't specifically solve my confusion.

I have been playing around with C for few months, and I always thought that sizeof(AnyStruct) will be a multiple of four, until I came to this:

#include <stdio.h>

typedef struct
{
    int x;
    char y;

} S1;

typedef struct
{
    char x[4];
    char y;
} S2;

int main()
{
    printf("%d\n", (int)sizeof(S1));
    printf("%d\n", (int)sizeof(S2));
    return 0;
}

The output is

8
5

Any explanation on why alignment didn't work in S2 but worked in S1 ?

In general, when does it work and when it doesn't, and how it works.

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
Youssef13
  • 3,836
  • 3
  • 24
  • 41
  • You might specify which answers you found and in how far your problem is different. – Gerhardh Jan 07 '20 at 14:57
  • Does this answer your question? [Structure padding and packing](https://stackoverflow.com/questions/4306186/structure-padding-and-packing) – Guillaume Petitjean Jan 07 '20 at 14:58
  • What do you mean with "alignment works"? Why do you expect to get 8 in both cases? – Gerhardh Jan 07 '20 at 14:58
  • sizeof returns the actual size in bytes of the subject passed to it, the only variable is depending on your system, int is either 16 bit (2 bytes) or 32 bit (4 bytes), so in your example S1 will be 3 if int is 16 bit and 5 is int is 32 bit. S2 will be 5 based on a char being 1 byte. – SPlatten Jan 07 '20 at 15:02
  • BTW, `sizeof` yields a `size_t` and the corresponding printf conversion specifier is `%zu`: `printf ("%zu\n", sizeof (S1));`. Kill a cast whenever you can. – Jens Jan 07 '20 at 15:04
  • There is padding between struct members, helps to get the member aligned. And the less obvious kind, padding at the end. The basic rule is that the struct members still need to be aligned when you store them in an array. That requires the one with the *int* member to be padded to 8 bytes. – Hans Passant Jan 07 '20 at 15:14
  • In C11 you can do `printf("%d %d\n", (int)sizeof(S1), (int)_Alignof(S1));` and it will print `8 4` and `5 1` for S1 and S2 respectively. The former being the actual size, the latter the alignment requirement. – Lundin Jan 07 '20 at 15:22
  • See http://www.catb.org/esr/structure-packing/ for all the gory details on padding. – dbush Jan 07 '20 at 15:34
  • @SPlatten: No. The size of `S1` will be the size of `int` as determined by the C implementation (not “the system”) plus the size of `char` plus the amount of padding the C implementation inserts between them plus the amount of padding the C implementation appends after them. Typical C implementation will insert no padding between them and enough padding after them to align to the same as the width of the `int`, resulting in a size that is twice that of `int`, but other results are possible too (such as 6 resulting from four-byte `int` that require two-byte padding). – Eric Postpischil Jan 07 '20 at 15:55
  • @EricPostpischil, by system I meant the software package employed. – SPlatten Jan 07 '20 at 16:18

1 Answers1

3

Structs are aligned to a multiple of the size of the member with the largest alignment requirement. If all elements are char, alignment requirement is 1.

This way an array of structs always has the size element size x number of elements, which is a nice property of the C programming language, since it makes dynamic allocation of arrays of any type straightforward.

Jens
  • 69,818
  • 15
  • 125
  • 179
  • isn't the array of 4 chars an element of size 4 ? Or I should consider *as if* it was 4 different elements each of type char ? – Youssef13 Jan 07 '20 at 15:04
  • 1
    @Youssef13 Every type has a size and an alignment. It seems on your system, `int` has size 4 and alignment 4: probably accessing an `int` is more efficient if the address is a multiple of 4. But there's no such benefit for `char` objects, so the type `char[4]` has size 4 and can just have alignment 1. – aschepler Jan 07 '20 at 15:22
  • 1
    @Youssef No, the alignment requirement for an array is the alignment of its element type. Why should a `char[93]` array be aligned to addressed divisible by 93? – Jens Jan 07 '20 at 16:15
  • @Jens, I've found some example, which I really can't understand. I'd be glad if you update the answer and explains it. `struct U { char ch[30]; unsigned int month:5; unsigned int day:4; unsigned int age:3; };` It gives 36 on Windows, but 32 on Linux. I really can't understand why 36 on Windows ? 32 is a multiple of 4 and it will fit those values. – Youssef13 Jan 08 '20 at 17:51