Почему «Каждое константное выражение должно иметь значение...» вместо «Каждое вычисленное константное выражение должно иметь значение...»?

n3301, 6.6 Константные выражения, п4 (выделено нами):

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

n3301, 6.5.15 Логический оператор ИЛИ, p4 (выделено нами):

Если первый операнд при сравнении не равен 0, второй операнд не оценивается.

Вопрос: почему 1-е требование не зависит от требования вычисления (или невычисления) такого константного выражения?

Другими словами: почему «Каждое константное выражение должно иметь значение...» вместо «Каждое вычисленное константное выражение должно иметь значение...»?

Это упущение?


Причина вопроса: некоторые люди считают, что «Каждое константное выражение должно иметь значение...» имеет приоритет (т. е. более сильное, имеет больший приоритет) над «вторым операндом не оценивается».

Да, у n3301 есть сноска 119:

  1. Таким образом, при следующей инициализации
static int i = 2 || 1 / 0;

выражение является допустимым целочисленным константным выражением со значением один.

Однако «В стандартах ISO примечания без исключения являются ненормативными.»

6.5.15 < 6.6 ... так логично или имеет приоритет над постоянным выражением. Просто шучу :)
pmg 03.09.2024 11:40

Как вы думаете, почему 2 || 1 / 0 не является константным выражением? Он «вычисляет константу, которая находится в диапазоне представимых значений для ее типа. Другими словами, можете ли вы привести пример константного выражения, которое не вычисляется?

ikegami 03.09.2024 11:47

@ikegami не является операндом и выражением? Тогда это правило будет применяться к каждому из задействованных выражений. И 1/0 никогда не будет оценен.

Gerhardh 03.09.2024 11:54

@Gerhard, Да, это было бы правильное выражение. Но что с того? Тот факт, что 1 / 0 не является допустимым константным выражением (например, нельзя использовать case 1 / 0), не означает, что оно не может быть его частью.

ikegami 03.09.2024 11:55
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
74
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Цитата, о которой идет речь, является частью определения константного выражения. Правило грамматики используется в тех местах, где ожидается, что код будет оцениваться во время компиляции. Это означает, что константные выражения обычно оцениваются безоговорочно (во время компиляции). Введение концепции константного выражения, которое не вычисляется, бесполезно и ненужно.


2 || 1 / 0 является допустимым константным выражением, поскольку это допустимое условное выражение, удовлетворяющее ограничениям константного выражения.

Соответственно, его значение равно 1, поэтому оно «вычисляет константу, находящуюся в диапазоне представимых значений для своего типа».

Оценка 2 || 1 / 0 не оценивает 1 / 0, но это не значит, что 2 || 1 / 0 нельзя оценить.

Следовательно, 2 || 1 / 0 можно использовать там, где ожидается константное выражение. Например, case 2 || 1 / 0 допустимо (хотя и довольно странно).

Демо в Compiler Explorer.


Хотя 1 / 0 является допустимым условным выражением, оно не соответствует ограничениям константного выражения, поэтому оно не является допустимым константным выражением.

В частности, он не «вычисляет константу, находящуюся в диапазоне представимых значений для ее типа».

Следовательно, 1 / 0 нельзя использовать там, где ожидается константное выражение. Например, case 1 / 0 недопустимо.

Демо в Compiler Explorer.

Спасибо. Я перепутал «постоянное выражение» с «постоянным подвыражением».

pmor 03.09.2024 20:10

Дополнительные вопросы: 1) Означает ли это, что стандарт C не требует, чтобы каждое константное подвыражение возвращало константу, находящуюся в диапазоне представимых значений для ее типа? 2) Приоритет оператора / выше приоритета оператора ||. Означает ли это, что при вычислении 2 || 1 / 0 компилятор C может сначала оценить 1 / 0, скажем, <invalid>, а затем оценить 2 || <invalid> как 2? 3) В каком порядке вычисляет типичный компилятор C (например, GCC, Clang, MSVC, ICC) 2 || 1 / 0?

pmor 03.09.2024 21:54

1) Не существует правила под названием «подвыражение» или «постоянное подвыражение». 2) Нет, из-за короткого замыкания ||. RHS оценивается только в том случае, если LHS истинен. В своем вопросе вы процитировали соответствующее правило. 3) Он не должен оценивать правую часть ||. Поэтому он должен создавать код, который генерирует 1.

ikegami 03.09.2024 22:12

Часть вопроса заключается в том, каково постоянное выражение в (ненормативном) примечании:

статический int я = 2 || 1/0;

Если это все выражение i = 2 || 1 / 0, то его можно вычислить, поскольку правило сокращения слева направо (что в a || b, если a истинно, то b не оценивается) означает, что константное выражение действительно оценивается как константа в представимом диапазоне.

И это несмотря на то, что подвыражение 1 / 0 не может быть вычислено (вообще), не говоря уже о константе, которую можно представить...

Я понимаю точку зрения ОП. Я думаю, что делаю вывод, что постоянное выражение — это вся правая часть присваивания. Это полезная интерпретация.

Я не думаю, что спецификация не совсем понимает, что такое постоянное выражение. Помогло бы что-то вроде «Константное выражение — это выражение, которое может быть вычислено во время перевода», и это отличается от «Константное выражение может быть вычислено во время перевода». Я читаю «можно» в отличие от «есть», «должен» или даже «должен».

Спецификация далее определяет константные выражения и даже допускает расширения, зависящие от реализации.

Там также говорится: «Семантические правила для вычисления постоянного выражения такие же, как и для непостоянного выражения». выражения». и содержит (ненормативное) примечание к приведенному выше примеру.

Но педантично, что (по крайней мере, в принципе) это не противоречит тому, что (суб-)выражение 1/0 квалифицируется как постоянное выражение.

Это определенно вопрос языкового юриста, потому что я думаю, что люди, знакомые с C, знают намерение авторов, вопрос в том, достигли ли они его совершенно однозначно и точно.

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