C99: Flexible array inside union?
Asked Answered
N

2

8

I tried to convert something from using the struct hack to using a flexible array member, only to run into the following error message:

error: invalid use of structure with flexible array member

(GCC 4.8.1, gnu99, MinGW)

After trying to track down the cause of the message, I distilled it down to the following relatively-minimal case:

struct a {
    union {
        struct {
            int b;
            int c[];
        } d;
    } e;
};

In other words, a struct with a flexible array member doesn't see to be able to be put inside a union in a struct, even if the union is the last member of the struct.

(Note that putting a flexible array member directly inside the union does seem to work.)

Now: is there any good way to work around this besides reverting back to the struct hack (declaring c as an array of length 1)? A pointer to a struct inside the union would work, but suffers an additional layer of indirection.

Neddy answered 8/6, 2014 at 17:28 Comment(0)
D
4

The C11 standard (ISO/IEC 9899:2011) says:

§6.7.2.1 Structure and union specifiers

¶18 As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member.

In the example you have, the last member of struct a is not a flexible array member. It is a union containing a struct that has a flexible array member.

You have to work quite hard to get gcc to complain, though; it requires -pedantic amongst the compiler options.

Dellora answered 8/6, 2014 at 20:36 Comment(4)
Nice catch! In other words, removing the outer struct would make the code valid. I am surprised that it takes pedantic as it's usually used for catching extensions. Does it mean it's OK in gcc land?Twentyfour
Yes; with the outer struct removed, the code compiles even under -pedantic (GCC 4.9.0 and gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -pedantic)Dellora
I know it doesn't work. It's nice to know why it doesn't work. However, that doesn't actually answer my question: how do I work around it?Neddy
The short answer is you probably continue using the struct hack until you can redesign the structures so that it isn't necessary. Note that struct a could not contain anything after the union (because of the way the layout would work). Or go with the extra level of indirection from using a pointer to the struct with the flexible array member. I suggest measuring performance before rejecting that solution.Dellora
S
1

The standard forbids this in section 6.7.2.1, Structure and union specifiers, paragraph 3:

A structure or union shall not contain a member with incomplete or function type [...], except that the last member of a structure with more than one named member may have incomplete array type; such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array.

A way around this would be to move the other elements of the outer struct into the inner structs, so that the outer struct is no longer necessary and the union can become the top-level element. For example, move the member mode of a struct like

struct item {
    int mode;
    union {
        struct {
            double a;
        } option1;
        struct {
            long b;
            int c[]; // not allowed
        } option2;
    };
};

to the top of each of the structs contained in the union:

union item {
    struct {
        int mode;
        double a;
    } option1;
    struct {
        int mode;
        long b;
        int c[];
    } option2;
};

Note that it is permitted to access mode through the wrong union member, because it is part of the common initial sequence that the two structs share.

Sukiyaki answered 12/5, 2020 at 11:24 Comment(1)
Interesting. Is there a way to do this if option2_s is not an anonymous struct, that doesn't raise the size of option2_s by the entire toplevel prefix? (Sorry if I overly-zealously minimized the example back in 2014 when I asked the question.)Neddy

© 2022 - 2024 — McMap. All rights reserved.