Должен ли троичный оператор оцениваться статически, когда это возможно? - PullRequest
3 голосов
/ 21 мая 2019

Требуется ли, чтобы троичный оператор оценивался статически, когда это возможно, или компилятор может отложить его на более поздний срок и, следовательно, отклонить программу, которая будет зависеть от его статической оценки?

Точнее, вот неоднозначный фрагмент программы:

char b[sizeof(a) > 10 ? 10 : sizeof(a)] = {0};

В зависимости от того, является ли a массивом переменной длины или нет, фрагмент является недействительным или нет. Если a является VLA, то sizeof(a) не определяется статически, и поэтому инициализация не может быть выполнена:

int main(int argc, char **argv) {
  int a[argc];
  char b[sizeof(a) > 10 ? 10 : sizeof(a)] = {0}; // invalid
  return 0;
}
error: variable-sized object may not be initialized

Но если a не является VLA, то все может быть оценено статически:

int main() {
  int a[42];
  char b[sizeof(a) > 10 ? 10 : sizeof(a)] = {0}; // valid
  return 0;
}

Мой вопрос: являются ли компиляторы, соответствующие стандарту требуется для статической оценки, когда это возможно, и поэтому должен принять вторую программу или им разрешено "отложить ее до динамической оценки" "и может отклонить это?

Ответы [ 2 ]

5 голосов
/ 21 мая 2019

Во втором случае:

int a[42];
char b[sizeof(a) > 10 ? 10 : sizeof(a)] = {0};

Выражение sizeof(a) > 10 ? 10 : sizeof(a) считается константным выражением , как определено в разделе 6.6 C стандарта , и также является целочисленным константным выражением .

Из раздела 6.6p3 указаны ограничения для константного выражения:

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

Вышеприведенное выражение не содержит ни одного из запрещенных операторов.

В разделе 6.6p6 уточняются целочисленные константы:

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

И сноска 117:

117) Требуется целочисленное константное выражение в числе контекстов, таких как размер члена битового поля структура, значение константы перечисления, и размер массива не переменной длины. Дополнительные ограничения, которые применяются к целочисленные константы выражения, используемые в условном включении директивы предварительной обработки обсуждаются в 6.10.1

Поскольку a не является массивом переменной длины, sizeof(a) оценивается как целочисленная константа. И поскольку sizeof(a) > 10 ? 10 : sizeof(a) содержит только 10, который является целочисленной константой, sizeof(a), который оценивается как целочисленная константа, и операторы ?: и >, которые не являются запрещенными операторами, все выражение считается целочисленное константное выражение и может использоваться как размер массива не переменной длины, что означает, что вы можете его инициализировать.

4 голосов
/ 21 мая 2019

«Оценивается статически» не определяется стандартом C.

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

C 2018 6.6 6 определяет целочисленное постоянное выражение :

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

Таким образом, в char b[sizeof(a) > 10 ? 10 : sizeof(a)]вопрос в том, имеет ли sizeof(a) результат, который является целочисленной константой.C 6.5.3.4 2 сообщает нам:

Оператор sizeof возвращает размер (в байтах) своего операнда, который может быть выражением или именем типа в скобках.Размер определяется по типу операнда.Результатом является целое число.Если тип операнда является типом массива переменной длины, операнд оценивается;в противном случае, операнд не оценивается, и результатом является целочисленная константа.

Таким образом, если a не является массивом переменной длины, результатом является целочисленная константа.Если a является массивом переменной длины, результатом является целое число, но неявно не целочисленная константа.

Таким образом, если a является массивом переменной длины, то char b[sizeof(a) > 10 ? 10 : sizeof(a)] объявляет переменную длинумассив.Использование троичного оператора не имеет значения, поскольку определение основано на том факте, что выражение содержит операнды, которых нет в списке, приведенном в 6.6 6, а не на том, присутствует ли троичный оператор.

Если a не является массивом переменной длины, тогда char b[sizeof(a) > 10 ? 10 : sizeof(a)] объявляет массив известного постоянного размера.Опять же, троичный оператор не имеет значения;определение в 6.6 6 не упоминает об этом.Таким образом, размер массива является целочисленным выражением с постоянной величиной, и соответствующая реализация C должна принять b в качестве массива с постоянным размером и разрешить его инициализацию.

Существует одно исключение из вышеприведенного.C 2018 6.6 10 говорит:

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

Таким образом, в теории теоретически можно определить sizeof(a) > 10 ? 10 : sizeof(a) как константное выражение,Опора на это, конечно, не будет переносимой.

...