Почему тернарное расширение GCC не поддерживает присваивание?

GCC имеет отличное расширение троичных выражений для C что позволяет нам создать такой оператор:

int x = some_var ?: 10; // expands to some_var ? some_var : 10

Что действительно приятно, и хотя это не особенно интуитивно понятно, оно работает. Большинство бинарных операторов в языке C имеют связанный с ними дополнительный оператор, который позволяет выполнять присваивание:

x = x + 2;

// instead, we can say
x += 2;

Поскольку это так и является нормой для большинства бинарных операторов C (+, -, *, /, %, |, &, ^), почему это не относится к тернарному оператору расширения:

int x = ...;
x ?:= 2; // error: Expected expression before '=' token

// which would expand to
x = x ?: 2;

Единственными операторами, которые не поддерживают это в стандартном C, являются логические операторы (||, &&), под которые определенно тернарный код не подпадает, так почему же мы не можем этого сделать?

Я бы очень хотел сделать смайлик с классной прической в ​​своем коде, но не могу! Было ли это упущением при разработке оператора или преднамеренным и где-то задокументированным? Является ли это результатом короткого замыкания оператором своего операнда или что-то совершенно другое?


person Richard J. Ross III    schedule 04.06.2013    source источник
comment
Не уверен, что означает x ?:= 2;, но, возможно, x ?= ValueWhenXTrue:ValueWhenXFalse;.   -  person chux - Reinstate Monica    schedule 04.06.2013
comment
Я не понимаю, почему этот вопрос «неконструктивен». Он полностью соответствует теме, обсуждает поведение конкретного оператора в GNU C. Он правильно помечен, дает простые конкретные примеры и дает окончательный ответ.   -  person Richard J. Ross III    schedule 04.06.2013
comment
@chux На человеческом языке это означало бы if x is zero, set it to 2.   -  person Richard J. Ross III    schedule 04.06.2013
comment
Какова будет семантика x ?:= 2? В выражении: a = x ? b : c четыре операнда, в расширении a = x ?: b три, в вашем предложении a ?:= b всего два - значение присваиваемое и значение подлежащее присвоению, а условного нет - вы сделали его бессмысленным - там не имеет разумной семантической интерпретации.   -  person Clifford    schedule 04.06.2013
comment
@Clifford условием будет значение lvalue, которое вы назначаете.   -  person Richard J. Ross III    schedule 04.06.2013
comment
Я совершенно уверен, что это приведет только к ответам, содержащим личные мнения разных людей, без указания каких-либо источников, поэтому это неконструктивно. Кроме того, в вопросе содержится много ваших личных, субъективных мнений о различных малопонятных операторах, изложенных как абсолютная истина. Я действительно не понимаю, насколько int x = some_var ?: 10; крут, решит любую программную проблему или сделает код менее запутанным.   -  person Lundin    schedule 04.06.2013
comment
@Lundin данные ответы не делают сам вопрос плохим. Да, я использовал некоторую гиперболу, но это сайт, редактируемый сообществом - не стесняйтесь изменять мой вопрос, если вы чувствуете, что что-то не так.   -  person Richard J. Ross III    schedule 04.06.2013
comment
Ну... не вижу смысла в несуществовании оператора ?:=. Давайте присоединимся к WG14 и предложим изменение Стандарта (возможно, оно попадет в следующий Стандарт).   -  person pmg    schedule 04.06.2013
comment
@RichardJ.RossIII: Тогда вам следует отредактировать вопрос, чтобы прояснить семантику, а не объяснять в комментарии. Вы не можете предложить модификацию или расширение стандарта, не сделав предложение по крайней мере столь же недвусмысленным, как и сам стандарт. Эта дискуссия уже высосала из нас больше жизни, чем когда-либо спасет такая функция!   -  person Clifford    schedule 05.06.2013


Ответы (1)


Чтобы ответить на этот вопрос, я считаю, что есть некоторые другие вопросы, на которые также необходимо ответить.

Почему в языке C есть оператор ?: и почему он лучше, чем if-else?

Насколько мне известно, никто не смог ответить на этот вопрос, не высказав лишь своего субъективного мнения. K&R 2.11 утверждает, что

«Условное выражение часто приводит к краткому коду».

а затем они иллюстрируют это строкой

printf("%6d%c", a[i], (i%10==9 || i==n-1) ? '\n' : ' ');

что является их собственным субъективным, мутным мнением. Лично я считаю, что

printf("%6d", a[i]);

if(i%10==9 || i==n-1)
  printf("\n");
else
  printf(" ");

намного, намного понятнее, поскольку я могу прочитать и понять этот код за 10 секунд, а не за 1 минуту, чтобы прочитать и понять версию K&R. Кроме того, мой код отделяет целочисленную печать от несвязанного форматирования. Но, конечно, это мое субъективное мнение, тут нет очевидных правильных или неправильных решений.

Что касается официальных источников, в обосновании C99 версии 5.10, 6.5.15 также не упоминается, зачем нужен оператор ?:. В основном просто говорится, что поведение оператора было изменено в новом стандарте:

Синтаксические ограничения на средний операнд условного оператора были ослаблены, чтобы включить больше, чем просто логическое ИЛИ-выражение: несколько существующих реализаций приняли эту практику.

Тип выражения условного оператора может быть void, структурой или объединением; большинство других операторов не работают с такими типами. Однако правила балансировки типа между указателем и целым числом были ужесточены, поскольку теперь только константа 0 может переносимо быть приведена к указателю.

Поэтому, если у кого-то возникнет желание выполнить арифметические действия над типами структур или объединений, ?: предположительно более удобен, чем if-else. Я не вижу в этом явной пользы, но это хоть какая-то причина для существования оператора.

Тогда следующим вопросом будет:

Почему в компиляторе GCC существует расширение компилятора для операнда ?:?

Ответ на этот вопрос упоминается здесь:

Когда это становится полезным, когда первый операнд содержит или может (если это аргумент макроса) содержать побочный эффект. Тогда повторение операнда в середине вызовет побочный эффект дважды. При пропуске среднего операнда используется уже вычисленное значение без нежелательных последствий его повторного вычисления.

Таким образом, это расширение GCC не имеет ничего общего с удобочитаемостью или согласованностью языка, оно было просто добавлено, чтобы избежать нежелательных побочных эффектов.

Затем, чтобы попытаться ответить на исходный вопрос:

Почему тернарное расширение GCC не поддерживает присваивание?

Вероятно, потому, что доступ к lvalue в условии присваивания обычно не приводит к каким-либо нежелательным побочным эффектам. x = x ? : 2; будет иметь нежелательные побочные эффекты только в том случае, если x будет объявлен как volatile - чтение изменчивой переменной является побочным эффектом. Таким образом, единственное практическое применение, которое я вижу в x ?:= 2;, состоит в том, чтобы предотвратить двойное обращение к одной и той же изменчивой переменной в одном и том же условном выражении.

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

Я также не могу найти никаких официальных или канонических источников, указывающих на какое-либо использование самого оператора ?:, кроме традиции и субъективных предпочтений стиля кодирования.

person Lundin    schedule 04.06.2013
comment
Возможно, необычно, но мы согласны ;-) K&R удалось выстрелить себе в ногу, используя пример, который, вероятно, менее ясен, чем альтернатива. ?: действительно может сделать код более кратким и ясным — однако их пример не является одним из них! Оператор позволяет использовать выражение там, где в противном случае потребовался бы поток управления, и это иногда бывает полезно. - person Clifford; 05.06.2013