How does padding of structs inside unions work?
Asked Answered
V

4

5

I have the following:

#include <stdio.h>

typedef union u_data
{
        struct
        {
                int a;
                int b;
                int c;
        };
                int elem[3];
}       my_data;

int     main(void)
{
        my_data data;

        data.a = 3;
        data.b = 5;
        data.c = -3;
        printf("%d, %d, %d\n", data.elem[0], data.elem[1], data.elem[2]);
}

and it works as I expected with output: 3, 5, -3

however I understand that structs can have padding in them so does that mean that the elements in the struct might not always align with the array?

Viviennevivify answered 24/11, 2017 at 10:36 Comment(6)
Accessing a different member of a union than the last one written to causes undefined behaviour. So: Yes, in the sense of "could be nasal demons".Redeemer
@Redeemer No, C standard makes an exception for unions (excluding possible trap representations). Padding issue asked here is different issue.Lowkey
just as a bit of context as to why i asked... i initially saw #8933207 with the second comment doing what i am doingViviennevivify
@Lowkey I accept that I might be wrong. But could you explain in more detail and in relation to the upvoted (and downvote-free) answer by gsamaras, which seems to say the same. What is the relevant difference?Redeemer
@Redeemer This recent answer talks about union member access. This question has only ~30 views so far so it's too early to use votes as metric for correctness.Lowkey
@Lowkey Very interesting standard quotes in that answer, thank you. Now I just have to dig up the things I read about switch-member-access being undefined and compare... But that is of course not to be discussed here.Redeemer
S
4
  • First of all, there is a special rule "common initial sequence" for unions in C, C11 6.5.2.3:

    One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible.

    This rule does not apply here though, since your case is a struct and an array. Had it been two structs, the rule would have applied.

  • Indeed a struct may have padding, so you are not guaranteed to get the correct output if the array is aligned differently than the struct. This is implementation-defined behavior.

  • Writing to the struct and reading from the array is fine and well-defined in C (unlike C++), C11 6.5.2.3/3, given that the two types are compatible. The struct can only be compatible with the array if there are no padding bytes.

  • "Strict aliasing" does not apply here.

Summary: this is implementation-defined behavior. You may rely on a certain behavior on a certain system, if the compiler guarantees it. The code will not be portable.

Strangulate answered 24/11, 2017 at 11:1 Comment(2)
Is it useful for the first and largest part of the answer to explain a rule that does not apply and was not asked about?Saba
@EricPostpischil Yes, because others here just post "its undefined behavior" as a knee-jerk reaction. There are many cases in C where type punning is allowed, and it is important to point these out since C++ programmers tend to get this wrong - in C++, many of the cases would invoke UB.Strangulate
L
2

You cannot expect a, b, and c to be aligned with the elem array due to padding, as you correctly point out.

Any code that relies on the contrary is not portable C.

Lindell answered 24/11, 2017 at 10:41 Comment(0)
S
0

Padding may be introduced between struct's members to enforce the individual alignment requirements of the members.


and it works as I expected

It looks that in your case, the alignment requirements of the members are already fulfilled, and therefore padding is not being introduced, which results in the array mapping perfectly the struct.

does that mean that the elements in the struct might not always align with the array?

No, since padding may be introduced between the members of the struct.

Southey answered 24/11, 2017 at 10:50 Comment(0)
R
-2

does that mean that the elements in the struct might not always align with the array?

No.

Your code invokes Undefined Behavior.

The array elem is not obligated to be aligned (due to padding) to the fields of the struct.

Result answered 24/11, 2017 at 10:43 Comment(3)
All of this sounds wildly incorrect. Let me check with the standard.Strangulate
Ok checked the standard, the answer is partially incorrect. "When you access a, b, and c you should have first initialize them somehow. " is incorrect, it is not UB but implementation-defined."The array elem is not obligated to be aligned (due to padding) to the fields of the struct." is correct.Strangulate
I did agree with you initially (apart from the abc thing), but did you see the comments thread between user694733 and me? It seems (to my surprise) to indicate that there is no undefined behaviour. There is an interesting link, https://mcmap.net/q/197302/-is-it-safe-to-detect-endianess-with-union I decided not to try my hand at language lawyering...Redeemer

© 2022 - 2024 — McMap. All rights reserved.