Является ли индексирование строкового литерала константным выражением инициализатора?

Следующий код пытается использовать индексирование массива для строкового литерала в двух разных константных контекстах:

static char x = "abcx"[3];

_Static_assert ("abcx"[3] == 'x', "...");

Судя по Compiler Explorer, среди поставщиков инструментов есть четкое согласие, что делать это во втором контексте, который явно требует целочисленного константного выражения, недопустимо. Однако они, похоже, отличаются в первом контексте, который является только выражением арифметической константы, используемым в инициализаторе. GCC и Clang выделяются как реализации, которые позволяют это.

Само по себе это не интересно, потому что в параграфе 10 6.6 C11/C18 говорит, что "реализация может принимать другие формы константных выражений". Тем не менее, это выделяется в этом случае, потому что:

  • GCC и Clang оба принимают это молча с -pedantic (правда, подписание компилятором не означает, что код соответствует). Создание кода имеет смысл, так как его значение простое, но я бы ожидал предупреждения, если бы они думали, что это не соответствует, и они могут понять, действительно ли (они думают) это или нет, потому что...

  • для обоих компиляторов поведение недавно изменилось - Clang использовал, чтобы вызвать ошибку по этой причине до 3.8, в то время как GCC использовал, чтобы вызвать ошибку до 8.0. Эти версии вышли в 2016 и 2018 годах соответственно. Это говорит о том, что изменение было преднамеренным, но я еще не нашел примечаний к выпуску ни для одного из компиляторов, которые бы описывали этот уровень детализации.

Время изменения поведения позволяет понять, что это было связано с C18, но формулировка 6.6, похоже, не изменилась. Ограничения для целочисленных константных выражений остаются строгими (как показано во второй строке с ошибкой), и формулировка параграфа 9 кажется такой же, как и в C11, в частности, продолжая говорить, что "значение объекта не должно быть доступ с помощью этих операторов " (WRT [] и друзья).

Является ли первый контекст допустимой константой инициализатора при любом чтении стандарта, не считая параграфа 10? Могу ли я найти обоснование изменений в GCC/Clang?

1 ответ

Решение

6.6 Постоянные выражения, ¶8:

Выражение арифметической константы должно иметь арифметический тип и иметь только операнды, которые являются целочисленными константами, плавающими константами, константами перечисления, символьными константами, выражениями sizeof, результаты которых являются целочисленными константами, и выражениями _Alignof. Операторы приведения в выражении арифметической константы должны преобразовывать только арифметические типы в арифметические типы, кроме как как часть операнда, к оператору sizeof или _Alignof.

Строковый литерал не является допустимым ни одним из вышеуказанных 6 типов операндов, поэтому выражение не является выражением арифметической константы, если оно не принято как расширение.

Другие вопросы по тегам