Можно ли инициализировать переменную stati c с помощью константы stati c? - PullRequest
7 голосов
/ 05 апреля 2020

В этот ответ Мне в основном нужно static int n = -1; внутри функции. Я хотел избежать магических c чисел повсюду, поэтому я использовал это вместо:

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

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

Однако мне было указано, что это не соответствует стандарту, потому что sentinel не является время) константа.

Это имеет смысл для меня, так как я знаю, что постоянные целые числа были использованы в выражениях времени компиляции (например, размер массивов) в C ++. Однако g cc, clang и i cc> v16 компилируют этот код без предупреждения. Только я cc <= v16 и MSV C выдают это предупреждение / ошибку (см. <a href="https://godbolt.org/z/wWokT3" rel="nofollow noreferrer"> godbolt ).

Что говорит стандарт C? Меняется ли это между различными версиями стандарта (c90, c99, c11)? Если это не соответствует, можем ли мы получить предупреждение о g cc и clang? Если это соответствует, почему старые i cc и MSV C выдают ошибки?

1 Ответ

6 голосов
/ 05 апреля 2020

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 говорит: «Все выражения в инициализаторе для объекта, у которого есть stati c или продолжительность хранения потока, должны быть константными выражениями или строковыми литералами». sentinel явно не является строковым литералом. Это постоянное выражение? Постоянные выражения определены в 6.6. За одним исключением, они должны иметь операнды, которые являются целочисленными константами (то есть литералами, такими как 37), sizeof выражениями, которые дают целочисленные константы, _Alignof выражениями, константами с плавающей точкой, константами перечисления, символьными константами или унарные & выражения с определенными ограничениями. sentinel не является ни одним из них.

Исключением является то, что в параграфе 10 говорится: «Реализация может принимать другие формы константных выражений». Таким образом, G CC и другие компиляторы могут принять этот код, если они будут sh, и, следовательно, поскольку он принят соответствующей реализацией, он является соответствующим кодом. Однако, поскольку он определяется реализацией независимо от того, принят он или нет, он не является строго соответствующим кодом.

Это существенно похоже на предыдущие C стандарты, начиная с 1990 года, хотя есть небольшие изменения, такие как что _Alignof не было в ранних версиях стандарта.

...