Подробности того, что составляет постоянное выражение в C?

StackOverflow https://stackoverflow.com/questions/4893257

Вопрос

C определяет как минимум 3 уровня «постоянного выражения»:

  • постоянное выражение (неквалифицированное)
  • арифметическое постоянное выражение
  • целочисленное постоянное выражение

6.6 абзац 3 гласит:

<цитата>

Постоянные выражения не должны содержать присваивание, приращение, декремент, вызов функции, или операторы запятой, кроме случаев, когда они содержатся в подвыражении, которое не оценено.

Значит ли это, что 1,2 не является постоянным выражением?

Пункт 8 гласит:

<цитата>

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

Каковы операнды в коде (union { uint32_t i; float f; }){ 1 }.f? Если 1 является операндом, то это предположительно арифметическое постоянное выражение, но если { 1 } является операндом, то это явно не так.

Изменить: Еще одно интересное наблюдение: пункт 3 7.17 требует, чтобы результат offsetof был целочисленным постоянным выражением типа size_t, но стандартные реализации offsetof, насколько я могу судить, не Стандарт должен быть целочисленным постоянным выражением. Это, конечно, нормально, поскольку реализации разрешено (в соответствии с параграфом 10 6.6) принимать другие формы константных выражений или реализовывать макрос offsetof как __builtin_offsetof, а не через вычитание указателя. Однако суть этого наблюдения заключается в том, что если вы хотите использовать offsetof в контексте, где требуется целочисленное постоянное выражение, вам действительно нужно использовать макрос, предоставленный реализацией, а не использовать собственный.

Это было полезно?

Решение

Судя по вашему чтению, 1,2 не является постоянным выражением. Я не знаю, почему это не так, просто я согласен с вами, что это не так (несмотря на то, что, вероятно, так и должно быть).

6.5.2 определяет составные литералы как постфиксный оператор. Итак, в

родовое слово

Операнды - это (union { uint32_t i; float f; }){ 1 } и f для оператора .. Это не арифметическое постоянное выражение, поскольку первый аргумент является типом кода union, но это постоянное выражение.

ОБНОВЛЕНИЕ: я основывал это на другой интерпретации стандарта.

Мое предыдущее рассуждение заключалось в том, что (union { uint32_t i; float f; }){ 1 }.f удовлетворяет критериям постоянного выражения и, следовательно, является постоянным выражением. Я по-прежнему считаю, что оно соответствует критериям константного выражения (6.6 абзац 3), но не является ни одним из стандартных типов константных выражений (целочисленные, арифметические или адресные) и, следовательно, может быть константным выражением только в абзаце 6.6. 10, что позволяет использовать константные выражения, определяемые реализацией.

Я тоже хотел перейти к вашей редакции. Я собирался возразить, что «взломанная» реализация offsetof была константным выражением, но я думаю, что это то же самое, что и выше: оно соответствует критериям для постоянного выражения (и, возможно, константы адреса), но не является целочисленным постоянным выражением, и поэтому недействителен за пределами пункта 10 6.6.

Другие советы

Если бы 1,2 было постоянным выражением, это позволило бы компилировать такой код:

родовое слово

Я не знаю, истинная ли это причина, но могу представить, что выдача ошибки для этой (распространенной?) ошибки считалась более важной, чем превращение кода 1,2 в постоянное выражение.

ОБНОВЛЕНИЕ : как указывает R. в комментарии, код больше не является ошибкой компилятора с момента появления VLA.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top