1

I have the following structure of union and structs

union ab {
    struct {
        int a;
    } a_st;

    struct {
        int b;
    } b_st;
};

typedef struct c {
    union ab;
} c_st;

when trying to "reach" the union elements directly:

c_st c;
printf("%d\n", c.a_st.a);

the following compilation error raised:

error: 'c_st' {aka 'struct c'} has no member named 'a_st'

if I provide the union name inside of the 'c_st' struct (e.g. ab_un), it works, but then I need to call c.ab_un.a_st.a, which is less desired.

is it necessary evil or have I missed something here?

Thanks in advance

TomDov
  • 27
  • 7
  • https://stackoverflow.com/questions/3228104/anonymous-union-within-struct-not-in-c99 https://stackoverflow.com/questions/13624760/how-to-use-c-union-nested-in-struct-with-no-name, https://stackoverflow.com/questions/1972003/how-to-compile-c-code-with-anonymous-structs-unions –  Dec 10 '20 at 10:10
  • 1
    `struct c { union ab; }` Don't you get a warning? – KamilCuk Dec 10 '20 at 10:12
  • @Jean-ClaudeArbaut - the chosen answer from https://stackoverflow.com/questions/1972003/how-to-compile-c-code-with-anonymous-structs-unions worked, thanks! – TomDov Dec 10 '20 at 10:42
  • FYI, the C 2018 standard specifies anonymous members in 6.7.2.1 13. It says an anonymous member is specified by “a structure specifier with no tag” or “a union specifier with no tag.” In other words, `union ab;` does not specify an anonymous member; it has a tag and is a redeclaration of the `union ab` type (which has undefined behavior for other reasons). So an anonymous union member per 6.7.2.1 13 must have the form `union { member declarations here };`. (Since the `union ab;` declaration has undefined behavior by the standard, it can be used for an extension, as mentioned in answers.) – Eric Postpischil Dec 10 '20 at 12:49

2 Answers2

0

Per this answer, the solution for gcc is to compile with -fms-extensions.

Here is an example. Tested with Visual C++ and MSYS2 gcc 10.2. With this version of gcc, the -fms-extensions seems to be implied, and I get an error as mentionned in the comments if I compile instead with -fno-ms-extensions.

#include <stdio.h>

union ab {
    struct {
        int a;
    } a_st;
    struct {
        int b;
    } b_st;
};

typedef struct d {
    union ab;
    struct {
        int c;
    } c_st;
    
} d_st;

int main(void) {
    d_st x;
    printf("%zu\n", sizeof(d_st));
    x.a_st.a = 1;
    x.b_st.b = 2;
    x.c_st.c = 3;
    printf("a_st = %d\n", x.a_st.a);
    printf("b_st = %d\n", x.b_st.b);
    printf("c_st = %d\n", x.c_st.c);
    return 0;
}
  • Strange, [I get a lot of errors](https://godbolt.org/z/rMGWo3). – KamilCuk Dec 10 '20 at 10:28
  • thanks, interesting. i'm using gcc 8.4.0. can it be a bug in this gcc version? – TomDov Dec 10 '20 at 10:29
  • @TomDov Maybe you need to give the option `-std=c11` to gcc. According to [this](https://gcc.gnu.org/wiki/C11Status), anonymous structs and unions are supported since version 4.6. –  Dec 10 '20 at 10:34
  • @KamilCuk Indeed, it's strange. It compiles with `gcc -Wall -std=c11` without a warning, and runs as expected. It's the gcc from MSYS2, but I don't think this would make a difference. However, `cl /Wall` gives me a warning even with `/std:c11`. –  Dec 10 '20 at 10:36
  • [Msvc seems to eat it](https://godbolt.org/z/rra4c4). `union ab;` is not an anonymous union - it has a tag, `ab` is the tag. Anonymous union is an union without the tag (the name after `union`). – KamilCuk Dec 10 '20 at 10:41
  • 1
    @KamilCuk Wait, tag or identifier? –  Dec 10 '20 at 11:05
  • @Jean-ClaudeArbaut i've used c11, but the missing part was ```-fms-extensions``` figured out from your comment on the original question. since you were the first to note this, may you inline this in your answer to mark it the chosen one? – TomDov Dec 10 '20 at 11:07
  • 1
    There's just confusion. C standard is clear [C11 6.7.2.1p13](https://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p13) `An unnamed member whose type specifier is a structure specifier with no tag is called an anonymous structure`. It must be unnamed and have no tag. `struct ab;` has no name (no identifier), it has a tag - `ab`. The gcc documentation and microsoft documentation seem to use unnamed/anonymous synonymously. – KamilCuk Dec 10 '20 at 11:07
  • 1
    @TomDov Done. Actually, it alswo explains why it worked for me: contrary to what I believed, it makes a great difference that I tested with gcc from MSYS2 (that is, on Windows), because the option `-fms-extensions` is always on by dafault. –  Dec 10 '20 at 11:21
0

As an extension MSVC compiler (see Microsoft Specific Anonymous Structures) and gcc compiler with -fms-extensions (see gcc docs unnamed fields) support the syntax of unnamed structures. When using this extension it allows the code to compiler and access the unnamed structure members as if they were members of the containing structure.

If using this extension, the code will compile and access is fine, you just made a typo c_st should be d_st.

#include <stdio.h>
union ab {
    struct {
        int a;
    } a_st;
    struct {
        int b;
    } b_st;
};
typedef struct d {
    union ab;
} d_st;
int main(void) {
    d_st c;
    printf("%d\n", c.a_st.a);
}

Without using this extension, the code will not compile, as explained below.


is it necessary evil or have I missed something here?

I would say it's just evil. The problem is with the following part:

struct c {
   union ab;
};

It's the same as writing:

struct c {
};

You can put any type and follow it with a ;, like:

struct d {
   int; float; unsigned long long; FILE *; some_other_type;
};

union ab is just a type. The some_type ; doesn't declare anything, nothing happens. The language grammar just allows you to write just a type as an expression without an identifier (ie. it's used in function declaration like void func(char*, int)), but nothing happens and such expression has no meaning. Your struct c is just empty, it has no members, it's undefined behavior.

trying to "reach" the union elements directly:

You can't access them, because they don't exists. There are no elements inside struct c - it's empty.

You may duplicate code (possibly with a macro):

struct c {
    union {            // anonymous union
        struct {
            int a;
        } a_st;
        struct {
            int b;
        } b_st;
    };
};

and access via:

struct c C;
printf("%d\n", C.a_st.a);
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • ```union ab;``` is not nothing, it is unnamed union. https://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html#Unnamed-Fields – TomDov Dec 10 '20 at 10:42
  • `If -fms-extensions is used, the field may also be a definition with a tag such as` this is the important part. – KamilCuk Dec 10 '20 at 10:45