The following code is rejected by GCC and Clang (godbolt link):
struct thing;
typedef enum {
THING_TYPE_A,
THING_TYPE_B,
} thing_type_t;
typedef struct thing_a {
int i;
} thing_a_t;
typedef struct thing_b {
struct thing const *t;
} thing_b_t;
typedef struct thing {
thing_type_t type;
union {
thing_a_t a;
thing_b_t b;
} t;
} thing_t;
thing_t const *get_thing(void) {
static const thing_t s_thing = {
.type = THING_TYPE_B,
.t = {
.b = {
.t = &(thing_t) { .type = THING_TYPE_A, .t = { .a = { .i = 234 } } }
}
},
};
return &s_thing;
}
cppreference's page on Compound Literals says:
The unnamed object to which the compound literal evaluates has static storage duration if the compound literal occurs at file scope and automatic storage duration if the compound literal occurs at block scope (in which case the object's lifetime ends at the end of the enclosing block).
I believe that explains the compile error; the anonymous thing_t
whose address is used to initialize s_thing.t.b.t
has automatic storage duration and is therefore not a compile-time constant. If s_thing
is moved to file-scope, both Clang and GCC accept it. (There is more discussion at this SO question)
It looks like C23 will expand this by allowing constexpr
to be specified inside the compound literal parentheses, which is a welcome improvement!
In the meantime, is there any way to achieve a declaration like s_thing
(that is, the initialization of a static const struct that contains a pointer to another constant variable) in pre-C23 at block scope, without having to explicitly declare the anonymous thing_t
as its own separate variable?