7

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?

5
  • 1
    6.6p10: "An implementation may accept other forms of constant expressions." I don't remember when that was introduced, but I'm pretty sure it was in C99. Commented Apr 5, 2020 at 2:04
  • 5
    If you consider -1 to be a magic number, it's still a magic number whether you initialise n or sentinel with it. Magic numbers are things that make no sense without context or domain knowledge, such as 1440 or 2.828. Just use -1 with the comment // This is the sentinel value, problem solved. If you really don't want any magic numbers, put them in magic_numbers.h with a comment for every one. Commented Apr 5, 2020 at 2:08
  • @rici: “An implementation may accept other forms of constant expressions” was in C 1990. Commented Apr 5, 2020 at 3:25
  • @MarcoBonelli: I do not know what that document is, but it is dated 1988, so it is not the 1989/1990 C standard. The penultimate sentence of ISO/IEC 9899:1990 (E) 6.4 is “ An implementation may accept other forms of constant expressions.” Commented Apr 5, 2020 at 3:29
  • @EricPostpischil oh, you're right, sorry about that. I was looking at the wrong link and that is indeed C89, not C90. So apparently the change is between C89 and C90. My bad. Commented Apr 5, 2020 at 3:37

1 Answer 1

6

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.

Sign up to request clarification or add additional context in comments.

4 Comments

The exception is that paragraph 10 says “An implementation may accept other forms of constant expressions.” - Since this does not seem to be the case for C89 though (at least for the version I was able to find), this means GCC/clang or whichever compiler accepts static int n = sentinel is non-conforming, doesn't it? I tried that on Godbolt adding -std=c89 and no error or warning popped up. Or maybe this means -std=c89 == C90?
Getting back to the OP, this is not a constraint violation, so no diagnostic is required. Gcc could issue a warning, but apparently it doesn't.
since it is accepted by a conforming implementation, it is conforming code. is a very flexible reading of It defines a conforming program to be one that is “that is acceptable to a conforming implementation”. Using this logic, a program can use any extension provided by a conforming compiler, such as inline assembly and intrinsics and still be conforming.
@chqrlieforyellowblockquotes: Programs containing GCC inline assembly are conforming. The C standard is intended to allow extensions. It invites them. Only the strictly conforming core language is rigid. The language of conforming programs is flexible. Keep in mind when the C standard was started, there was a great variety in platforms where C was implemented. C provided a way to write code that was largely portable not just in today’s sense that it could be used without change but in the sense that it provided a common core so programs could be easily adapted to new implementations.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.