ideasman42
ideasman42

Reputation: 48058

Struct padding for single member structs

I was looking to make a struct which was an arbitrary size, known at compile time. (for use in a macro).

eg:

/* assume sizeof(SomeStruct) could be an odd number,
 * if it is using GCC's 'packed' attribute for eg */
struct {
    unsigned char data[sizeof(SomeStruct)];
} a, *tmp;

tmp = (void *)some_data
a = *tmp;

However I was concerned that struct padding may increase the size of the struct so it is larger than the member, I was assured that the size of a single member struct will always be the size of its member.

So my question is:

Can I rely on single member structs always being the same size as their member? Is this apart of the C spec? or is it just how most compilers behave?

Upvotes: 4

Views: 608

Answers (1)

Alex Celeste
Alex Celeste

Reputation: 13370

C11 6.7.2.1 paragraph 17:

There may be unnamed padding at the end of a structure or union.

No special case is listed for structs with only one member. This is implementation-defined.

It's not obvious why a compiler would put padding there though, since the size of the member should already be as padded as is necessary for all purposes, as it has a complete type of its own.


For your usage though, you don't need to rely on the compiler's behaviour - you can enforce it yourself by adding a static assertion to your macro that sizeof *tmp == sizeof (SomeStruct). If you have an up-to-date compiler and your macro allows for declaration statements, just use _Static_assert; there are also several C99-compatible hacks you can use, such as:

#define STATIC_EXPR_ASSERT(COND) (sizeof (char[(COND) ? 1 : -1]))

... which you can use as the lhs of a comma-expression.

You should also note that if the body of the temporary struct is made up of a char array, it may not have sufficient alignment to represent the incoming data correctly. From C11 onwards you should specify the alignment of the array with _Alignas:

struct {
    _Alignas (max_align_t) unsigned char data[sizeof(SomeStruct)];
} a, *tmp;

...which will ensure it can safely store the data for any type regardless of alignment. In C99 you don't have any way to explicitly request max alignment, but you can force the alignment to match a named type by making the temporary struct a member of a union alongside it (you might try long double and hope that's the most-aligned type).

Upvotes: 6

Related Questions