Как написать выражение a<=20?b=30:c=30; такое, чтобы 30 использовалось только один раз?

#c #operators #operator-precedence #conditional-operator

#c #операторы #оператор-приоритет #условный оператор

Вопрос:

Я читаю книгу по программированию на c и столкнулся с этим примером:

 a<=20?b=30:c=30;
  

Мне просто нужно использовать число 30 один раз. Решение в книге было

 ((a<=20)?amp;b:amp;c)=30);
  

Когда я пытаюсь запустить это, я получаю следующую ошибку:

значение lvalue требуется в качестве левого операнда присваивания.

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

Не могли бы вы сказать мне, как я могу это исправить?

Комментарии:

1. это выглядит как бессмысленное упражнение

2. *((a<=20)?amp;b:amp;c)=30;

3. Вы могли бы рассмотреть расширения GCC

Ответ №1:

предположим, что a и b являются числами одного и того же типа, просто сделайте

 *((a <= 20) ? amp;b : amp;c) = 30;
  

для получения адресов a и b необходимо разыменовать (‘*’), чтобы иметь значение lvalue

из замечания @Vrintle примечание, которое вы также можете сделать на C

 ((a<=20)?b:c)=30;
  

компилятор знает, что форма является значением lvalue, поэтому используются не значения b и c, а их ссылки

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

в ((a<=20)?amp;b:amp;c)=30); последнем ‘)’ нет соответствующего ‘(‘

Комментарии:

1. Разве это не было бы просто (a<=20?b:c)=30; хорошо?

2. @Vrintle нет, потому что вы получаете значение b или c , так что это все равно, что писать 10=20 , требуется значение lvalue

3. Кажется, все в порядке. Но я запустил его на TIO , cpp.sh и это не дало никаких ошибок. Почему так?

4. @Vrintle Я отредактировал свой ответ, спасибо за замечание, я просто просыпаюсь 😉

5. @Vrintle: он не дал ошибок при TIO или cpp.sh потому что вы скомпилировали его как C , а правила в C другие. В C (a <= 20 ? b : c) не является значением lvalue , поэтому оно не может быть левым операндом присваивания (в отсутствие расширения компилятора для языка). Согласно C 2018 6.3.2.1 2, значения l b и c преобразуются в значения в ? : выражении.

Ответ №2:

Для начала в C это выражение

 a<=20?b=30:c=30
  

эквивалентно

 ( a<=20?b=30:c ) = 30
  

и компилятор выдаст ошибку, потому что левый операнд присваивания не равен lvalue .

Вы должны написать

 a <= 20 ? b = 30 : ( c = 30 )
  

или для симметрии

 a <= 20 ? ( b = 30 ) : ( c = 30 )
  

Вы имеете в виду следующее

*( a <= 20 ? amp;b : amp;c ) = 30;

Это уловка получения ссылки на объект в значении C, которое косвенно через указатель на объект. Сам указатель имеет значение rvalue, но, разыменовывая его, вы получаете значение lvalue указанного объекта.

В C вы могли бы написать просто

 ( a <= 20 ? b : c ) = 30;
  

потому что в этом случае оператор возвращает значение lvalue .

Между C и C есть разница в определении грамматики условного оператора.

В C это определяется как (6.5.15 Условный оператор)

 conditional-expression:
    logical-OR-expression
    logical-OR-expression ? expression : conditional-expression
  

в то время как в C (C 14, 5.16 Условный оператор)

 conditional-expression:
    logical-or-expression
    logical-or-expression ? expression : assignment-expression
  

Итак, в C допустимо исходное выражение, которое не скомпилировано компилятором C

 a <= 20 ? b = 30 : c = 30
  

Комментарии:

1. вы уверены в приоритете?

2. @bolov Да, я уверен.

3. вы правы, я думал в режиме C . Не знал о разнице с C здесь.