静态变量可以用静态常量初始化吗?

Can a static variable be initialized with a static constant?

this answer 中,我基本上需要在函数中使用 static int n = -1;。我想避免到处都是幻数,所以我改用了这个:

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

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

但是有人向我指出这不符合标准,因为 sentinel 不是(编译时)常量。

这对我来说很有意义,因为我知道常量整数在 C++ 的编译时表达式(例如数组大小)中可用。但是,gcc、clang 和 icc >v16 会在没有任何警告的情况下编译此代码。只有 icc <=v16 和 MSVC 给出了这个 warning/error(参见 godbolt)。

C 标准怎么说?这在不同版本的标准(c90、c99、c11)之间会发生变化吗?如果这不符合,我们可以在 gcc 和 clang 上得到警告吗?如果符合,为什么旧​​的 icc 和 MSVC 会报错?

static const int sentinel = -1; static int n = sentinel; 符合 C 代码。它不严格符合 C 代码。

C 2018 将 严格符合的程序 定义为“应仅使用本文档中指定的语言和库的那些功能”(C 2018 4. 5)。严格符合标准的程序是那些只使用标准中完全定义的核心语言的程序。它定义了一个 符合程序 是一个“可以被符合的实现所接受”的程序 (4. 7)。对于托管实现,符合规范的实现 是接受任何严格符合规范的程序 (4. 6)——即支持核心 C 语言但也可能支持的任何编译器或其他实现有扩展。

6.7.9 4 说“具有静态或线程存储持续时间的对象的初始化程序中的所有表达式都应为常量表达式或字符串文字。” sentinel 显然不是字符串文字。是常量表达式吗?常量表达式在 6.6 中定义。除了一个例外,它们的操作数必须是整数常量(即 37 等文字)、产生整数常量的 sizeof 表达式、_Alignof 表达式、浮点常量、枚举常量、字符常量或具有特定约束的一元 & 表达式。 sentinel 是其中的 none 个。

例外情况是第 10 段说“实现可以接受其他形式的常量表达式。”因此,如果 GCC 和其他编译器愿意,可以自由地接受此代码,因此,由于它被一致的实现所接受,因此它是一致的代码。但是,由于它是否被接受是由实现定义的,因此它不是严格符合规范的代码。

这与 1990 年以前的 C 标准基本相似,尽管有一些小的变化,例如 _Alignof 不在标准的早期版本中。