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?

timrau
  • 22,578
  • 4
  • 51
  • 64
Theo Walton
  • 1,085
  • 9
  • 24
  • 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". – Yunnosch Nov 24 '17 at 10:41
  • 2
    @Yunnosch No, C standard makes an exception for unions (excluding possible trap representations). Padding issue asked here is different issue. – user694733 Nov 24 '17 at 10:47
  • just as a bit of context as to why i asked... i initially saw https://stackoverflow.com/questions/8932707/what-are-anonymous-structs-and-unions-useful-for-in-c11 with the second comment doing what i am doing – Theo Walton Nov 24 '17 at 10:48
  • @user694733 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? – Yunnosch Nov 24 '17 at 10:52
  • @Yunnosch [This recent answer](https://stackoverflow.com/a/47430774/694733) 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. – user694733 Nov 24 '17 at 11:02
  • @user694733 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. – Yunnosch Nov 24 '17 at 11:07

4 Answers4

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.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 1
    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? – Eric Postpischil Nov 24 '17 at 15:25
  • @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. – Lundin Nov 27 '17 at 08:05
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.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
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.

JFMR
  • 23,265
  • 4
  • 52
  • 76
-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.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • 2
    All of this sounds wildly incorrect. Let me check with the standard. – Lundin Nov 24 '17 at 10:53
  • 2
    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. – Lundin Nov 24 '17 at 11:02
  • 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://stackoverflow.com/a/47430774/694733 I decided not to try my hand at language lawyering... – Yunnosch Nov 24 '17 at 11:47