3

I have the following struct:

struct data {
        char buffer[12];
        bool flag;
}

When testing the size of the data structure, I realized it was 16 bytes because of the boolean flag which added 3 bytes in padding. So I decided to do the following while using the last byte of the buffer as the flag:

struct data {
        char buffer[16];
}

This way my buffer is 3 bytes larger for free as it would have been lost in padding anyway.

However, I want this structure to be platform independent, so I looked on cppreference and found the following (emphasis mine):

Every complete object type has a property called alignment requirement, which is an integer value of type size_t representing the number of bytes between successive addresses at which objects of this type can be allocated.

Based off this, I wrote the following:

struct data {
        char buffer[12 + sizeof(size_t)];
}

It works on my device, but I am just wondering if this is guaranteed to properly align on all platforms and not waste any bytes?

Edit: I am aware that sizeof(size_t) may be 8 bytes, making my structure 20 bytes. However, if the alignment is by 8 bytes, then my structure would be 20 bytes regardless. This is why I wish to know how the structure is aligned.

melpomene
  • 84,125
  • 8
  • 85
  • 148
Michael Smith
  • 1,271
  • 1
  • 8
  • 31

5 Answers5

3

Are structs guaranteed to be aligned to sizeof(size_t) in C?

No.


I suspect the following will meet OP's goal of getting access to the padding. Member order is important. Put smallest members last. char is always smallest.

struct data_ref {
  bool flag;
  char buffer[12];
};

#define PAD (sizeof(struct data_ref) - sizeof(char)*12 - sizeof(bool))

struct data {
  bool flag;
  char buffer[12 + PAD];
};
Stargateur
  • 24,473
  • 8
  • 65
  • 91
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • 2
    @Stargateur How would you suggest to use `offsetof` here? – chux - Reinstate Monica Apr 15 '18 at 17:27
  • it does not save any bytes it only makes sizeof struct smaller. And it is the truth if it the only one object. Otherwise it will add the padding after your structure. – 0___________ Apr 15 '18 at 17:38
  • that is a good question... never mind ! I uncomfortable with your example but... yeah something wrong but I don't know what. – Stargateur Apr 15 '18 at 17:38
  • @Stargateur Perhaps `#define PAD (sizeof(struct data_ref) - offsetof(data_ref, buffer)/*the last member*/ - sizeof(char)*12)`? This answer does not yet well handle a more complex `struct` with many members, yet your offset idea helps find the padding from the last member to the end. – chux - Reinstate Monica Apr 15 '18 at 19:15
1

Are structs guaranteed to be aligned to sizeof(size_t) in C?

No. Why would they be?

melpomene
  • 84,125
  • 8
  • 85
  • 148
  • I only thought this because of the quote I provided from cppreference. They state that all objects have a property of `alignment requirement`. – Michael Smith Apr 15 '18 at 17:14
  • @MichaelSmith Yes, all objects have an alignment requirement. What does that have to do with `sizeof (size_t)`? – melpomene Apr 15 '18 at 17:14
  • I think your answer is too long. "no" was enough. – Stargateur Apr 15 '18 at 17:15
  • @melpomene From the quote I provided: `which is an integer value of type size_t representing the number of bytes between successive addresses`. I am not sure if I misunderstood, but it seems they are saying the alignment is of type `size_t`. – Michael Smith Apr 15 '18 at 17:16
  • @MichaelSmith Yes, the alignment is of type `size_t`. E.g. `char` is an object type whose alignment requirement is `(size_t)1`. What does the type of the number have to do with its value? – melpomene Apr 15 '18 at 17:17
  • @melpomene Thanks, I misunderstood the type of the address for the actual size of the alignment. – Michael Smith Apr 15 '18 at 17:20
  • @MichaelSmith you misunderstood it again. – 0___________ Apr 15 '18 at 17:22
  • @PeterJ_01 How so? – Michael Smith Apr 15 '18 at 17:22
  • 2
    @MichaelSmith do not take it personally - but I think it is too early for you for this topic. You should just trust us and remember that your solution will not save you any bytes. – 0___________ Apr 15 '18 at 17:27
  • @PeterJ_01 `your solution will not save you any bytes` Is that so? The accepted answer directly contradicts that. – Michael Smith Apr 15 '18 at 17:30
1

The C standard does not dictate the alignment of fields within a struct. Section 6.7.2.1 p14 of the C standard states:

Each non-bit-field member of a structure or union object is aligned in an implementation-defined manner appropriate to its type.

So there's no guarantee that a given struct will be laid out the same way on two different compilations of the same source code, whether that be different compilers or the same compiler with different optimizations settings.

As a counterexample, given the following struct:

struct test1 {
    char s[13];
};

On my machine, sizeof(struct test1) evaluated to 13 and _Alignof(struct test1) evaluates to 1. In fact, I get the same result with your first definition of struct data, indicating that there's no padding.

So there is no guarantee that structs are aligned on a sizeof(size_t) boundary.

Regarding the quote you gave:

Every complete object type has a property called alignment requirement, which is an integer value of type size_t representing the number of bytes between successive addresses at which objects of this type can be allocated.

This states that all types have an alignment requirement, and that that value has a type of size_t, not that a type has to have an alignment of that sizeof(size_t).

That being said, there is a way that structs tend to be laid out, and you can typically reduce the size of the struct if you follow these conventions.

Generally speaking, the alignment requirement of a struct ends up being the largest alignment requirement of its fields, and the alignment requirement of an array is the same as that of its containing type. Also, a primitive type n bytes in size typically needs to be aligned on an n byte boundary. So when you have fields within a struct with different alignment requirements, padding will typically be inserted to ensure each field's alignment requirement is satisfied.

In the case of your structure, you have a char array whose element size is 1 and a bool whose size (on my machine at least) is also 1, so the struct as a whole has an alignment requirement of 1 and no padding is needed.

Making use of these properties, you can usually reduce the size of your structs. The Lost Art of Struct Packing goes into this in much more detail.

To reiterate however, the way fields in a struct are laid out is implementation defined according to the standard. So while you might be able to lay out your struct to minimize padding, there is still no guarantee that it will always be the same in all environments.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • just for this amazing link of The Lost Art of C Structure Packing, I need to be able to upvote more than one time ;) – Stargateur Apr 15 '18 at 19:07
0

Are structs guaranteed to be aligned to sizeof(size_t) in C?

No.

You've misunderstood the use of size_t in the quoted paragraph. The alignment of a type is a value of type size_t. For example, the alignment of type char is (size_t)1, and a structure containing only a single char member might itself have an alignment of (size_t)1. (Or it might have a larger alignment.)

size_t is just the type used to represent an alignment value. The size or alignment of the type size_t has nothing to do with the size or alignment of a structure -- unless the structure happens to have a member of type size_t.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
-3

struct's required alignment is measured by the biggest alignment of any of it's members.

i.e., a struct with only char types will be aligned on a char alignment (single byte for the most part).

a struct that contains an int (and sometimes bool is implemented using an int) will be aligned on an int alignment as well as include any required padding for the int in the struct to be aligned.

The logic behind this alignment scheme is for struct arrays.

i.e.:

/* assuming int requires a 4 byte boundary alignment */
struct example_s {
  char bytes[2];
  /* char padding[2]; //  2 byte padding so `int` is aligned */
  int i;
};

struct example_s example_array[10];

This will promise that the example_array[2].i is properly aligned.

Myst
  • 18,516
  • 2
  • 45
  • 67
  • If you're going to down vote - at least let me know why and what to fix. – Myst Apr 15 '18 at 17:19
  • all your answer is false according to the C standard. – Stargateur Apr 15 '18 at 17:21
  • @Stargateur - How so? my answer explains the struct alignment requirement according to the standard. What's false about it? – Myst Apr 15 '18 at 17:22
  • I didn't vote on your answer but it makes quite a strong claim without backing it up. Do you have any references to the standard to support it? – melpomene Apr 15 '18 at 17:22
  • @melpomene - there's a quote in the question that said pretty much the same thing (only it was misinterpreted by OP), it's generally referring to section 6.2.8 in the standard. – Myst Apr 15 '18 at 17:25
  • Wrong: but the alignment of the `struct` is probably the same as the maximal *alignment* (not size!) of members – Basile Starynkevitch Apr 15 '18 at 17:28
  • @BasileStarynkevitch - Cool, I'll fix that. However, it's worth pointing out that the size of the type and it's alignment requirement will calculate to the same number of bytes in all cases (except for bit fields). – Myst Apr 15 '18 at 17:30
  • 2
    Wrong: `alignof(char[15])` is 1, but `sizeof(char[15])` is 15 – Basile Starynkevitch Apr 15 '18 at 17:31
  • 1
    @BasileStarynkevitch The original answer referred to "size of type" not "size of member" - i.e. `sizeof (char), not `char a[15]; sizeof(a)`... but I can see where I might have been misunderstood. The updated answer is probably clearer, – Myst Apr 15 '18 at 17:34
  • Again `sizeof` and `alignof` are different – Basile Starynkevitch Apr 15 '18 at 17:35
  • 1
    @BasileStarynkevitch - where do you see `sizeof` in my answer? – Myst Apr 15 '18 at 17:37