Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a static variable be initialized with a static constant?

In this answer I basically needed static int n = -1; inside a function. I wanted to avoid magic numbers all over the place so I used this instead:

double f(int i)
{
    static const int sentinel = -1;
    static int n = sentinel;

    if (n == sentinel)
    // ...
}

It was however pointed to me that this is not conformant to standard because sentinel is not a (compile time) constant.

This makes sense to me since I know constant integers were made usable in compile time expressions (e.g. size of arrays) in C++. However gcc, clang and icc >v16 compile this code without any warning. Only icc <=v16 and MSVC give this warning/error (see on godbolt).

What does the C Standard say? Does this change between various versions of the standard (c90, c99, c11)? If this is not conformant, can we get a warning on gcc and clang? If it is conformant why do old icc and MSVC give errors?

like image 958
bolov Avatar asked Apr 05 '20 01:04

bolov


Video Answer


1 Answers

static const int sentinel = -1; static int n = sentinel; is conforming C code. It is not strictly conforming C code.

C 2018 defines a strictly conforming program to be one that “shall use only those features of the language and library specified in this document” (C 2018 4. 5). Strictly conforming programs are those that only use the core language that is fully defined in the standard. It defines a conforming program to be one that is “that is acceptable to a conforming implementation” (4. 7). For hosted implementations, a conforming implementation, is one that accepts any strictly conforming program (4. 6)—that is, any compiler or other implementation that supports the core C language but that may also have extensions.

6.7.9 4 says “All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.” sentinel is clearly not a string literal. Is it a constant expression? Constant expressions are defined in 6.6. With one exception, they must have operands that are integer constants (that is, literals such as 37), sizeof expressions that yield integer constants, _Alignof expressions, floating-point constants, enumeration constants, character constants, or unary & expressions with certain constraints. sentinel is none of these.

The exception is that paragraph 10 says “An implementation may accept other forms of constant expressions.” So, GCC and other compilers are free to accept this code if they wish, and therefore, since it is accepted by a conforming implementation, it is conforming code. However, since it is implementation-defined whether this is accepted or not, it is not strictly conforming code.

This is substantially similar in prior C standards back to 1990, although there are minor changes, such as that _Alignof was not in early versions of the standard.

like image 121
Eric Postpischil Avatar answered Oct 17 '22 03:10

Eric Postpischil