2

In C11 standard there is following definition of common initial sequence shared by structures nested within a single union:

6.5.2.3/6

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. Two structures share a common initial sequence if corresponding members have compatible types (and, for bit-fields, the same widths) for a sequence of one or more initial members.

EXAMPLE 3 The following is a valid fragment:

union {
    struct {
        int alltypes;
    } n;

    struct {
        int type;
        int intnode;
    } ni;

    struct {
        int type;
        double doublenode;
    } nf;
} u;

u.nf.type = 1;
u.nf.doublenode = 3.14;
/* ... */
if (u.n.alltypes == 1)
        if (sin(u.nf.doublenode) == 0.0)
            /* ... */

According to my understanding of this article, the above code, however, is invalid.

In the outer if statement we indicate that n::alltypes data member is active (simultaneously with ni::type and nf::type as the standard states) yet in the inner if we use nf::doublenode which is not a part of the common initial sequence.

Can somebody clarify this issue?

Quentin
  • 1,090
  • 13
  • 24
  • 1
    `nf.doublenode` is assigned right above the comment to `3.14`. The behavior has nothing to do with being "active simultaneously", it's just basics on how unions work. – obataku Aug 28 '12 at 18:04
  • What the code above does is create something akin to Pascal's variant records, you have a record/struct which can have different types depending on a selector field (in this case, `alltypes`/`type`). – ninjalj Aug 28 '12 at 19:32

1 Answers1

4

it is permitted to inspect the common initial part of [several structures that share a common initial sequence]

Using the provided example, this part of the specification is saying that since each possible member type of the union has an int as the initial field, you can access that common initial field using any of the member types, even after the variable has been initialized/used as one of the specific member types.

This is just what the example does: it accesses the initial int as the alltypes member of an n, after having initialized following fields as an nf, and then goes on to access the doublenode field of an nf, all using the same variable.

Using the union as one of the possible types doesn't force it into some sort of structure: this is how unions work.

Note that this guarantee has been around for some time: essentially the same text is found in the ANSI specification, section: 3.3.2.3 Structure and union members.

pb2q
  • 58,613
  • 19
  • 146
  • 147
  • Right, my bad. I don't know why, but I just thought that assigning a value to `u.nf.doublenode` would blur the content of `u.nf.type` - what is a complete nonsense as they appear in the same structure :) – Quentin Aug 28 '12 at 18:18
  • @Quentin similar usage _could_ "blur" the content of following fields, if they _aren't_ common. For example, after the code in the `if`, you can't access `u.ni.intnode` in a defined way. – pb2q Aug 28 '12 at 18:20
  • What does the C++ Standard say about whether a pointer to one member of a union may be used to inspect part of the common initial sequence of another member of the union, or about the applicability of the CIS rule to accesses via struct pointers in the absence of actual objects of union type? The CIS rule, as written, makes it possible to write functions that can accept a pointer to any structure type with a known initial sequence and inspect members of that initial sequence, but gcc's interpretation of c99 makes it useless for that purpose unless code uses `-fno-strict-aliasing`. – supercat Sep 07 '16 at 18:57