Search code examples
cconstantsstatic-initialization

"Initializer element is not constant" when defining an object as a static member of a function


The following code compiles without complaints:

struct s {
    const int a;
};

static const struct s *s = &(const struct s) {
    .a = 5
};

int main(void) {
    (void) s;
    return 0;
}

However, if we move the definition of s to the body of main, i.e.:

struct s {
    const int a;
};

int main(void) {
    static const struct s *s = &(const struct s) {
        .a = 5
    };
    (void) s;
    return 0;
}

we get the error:

error: initializer element is not constant
    static const struct s* s = &(const struct s) {
                               ^

Since, in both cases, we deal with static (i.e. compile-time) initialization, why is the second use case illegal? Is there any way to make it legal in the context of a function?

(I have checked this with GCC 7.3.0 and clang 6.0.0, and they both report this as an error)


Solution

  • Per C 2018 6.6 (“Constant expressions”) 7:

    More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following: … an address constant, or…

    Per 6.6 9:

    An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator…

    Then, in 6.5.2.5 (“Compound literals”) 5, we have:

    … If the compound literal occurs outside the body of a function, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block.

    Thus, in the first case, the compound literal is an object with static storage duration, and a pointer to it is an address constant. In the second case, the compound literal is an object with automatic storage duration, and a pointer to it is not an address constant.