Почему выражение c = (a + b) ++ не допускается в C? - PullRequest
0 голосов
/ 18 октября 2018

Я пытаюсь запустить часть кода, и мне пришлось увеличить значение комбинированного выражения a+b.Пытаясь сделать это, я написал утверждение

c=(a+b)++

Получив следующую ошибку в этом утверждении -
"выражение должно быть изменяемым значением"

ПочемуЯ получаю эту ошибку, и почему увеличение значения выражения не допускается в C?

Ответы [ 6 ]

0 голосов
/ 18 октября 2018

Существует путаница относительно значения приращения .В вашей задаче вы должны добавить единицу к выражению a + b, которое можно описать как , вычислить сумму a и b и увеличить на единицу .В Си оператор приращения ++ имеет очень специфическую семантику: он увеличивает значение скалярной переменной в качестве побочного эффекта и оценивает либо увеличенное значение, либо исходное значение в зависимости от того, помещено ли оно до или после указанной переменной.Существуют дополнительные ограничения, касающиеся типа объекта и использования того же объекта в другом месте в том же выражении.

Для вашей проблемы решение состоит в том, чтобы добавить 1 с помощью оператора сложения: a + b + 1

0 голосов
/ 18 октября 2018

C11 6.5.3.1p1 :

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

Это означает, что если у нас есть конструкция something ++, то something

  • должна быть действительной: целая или с плавающей запятой, но не можетможет быть комплексным числом
  • или может быть указателем типа (но указатель void не подходит, поскольку для него не определена арифметика)
  • также может быть _Atomic или volatile
  • , но это должно быть lvalue , т.е. обозначать объект , который изменяется с шагом
  • и этот lvalueдолжен быть изменяемым (например, он не может быть const квалифицированным)

Выражение

a + b

не является выражением lvalue, оно не обозначает объект.Это арифметическое выражение;и значение арифметического выражения не является lvalue.Хотя вы можете добавить 1 к этому значению, значение выражения не является объектом для изменения.


Однако, учитывая

int a, *b, c[5][6];
struct FOO { char *bar; } foo, *fooz;
double *funnyfunc(int x);

, все эти выражения являются изменяемыми скалярными lvalues:

a
*(b + 5)
c[1][4]
foo.bar
fooz->bar
funnyfunc(5)[42]

и вы можете применить к ним ++.


Есть еще одна проблема с

c = (a + b) ++

значением постинкрементавыражение - это значение перед шагом , т. е. даже если бы это a + b было изменяемым, c не имело бы значения a + b + 1, но в любом случае a + ba + b изменит свое сохраненное значение для последующих оценок.

0 голосов
/ 18 октября 2018

легко запоминаемое выражение:

LValue - левое значение

LValue должно быть контейнером.Другими словами, область памяти, которая может хранить что-то и не ограничивается этим И, переменные являются единственными контейнерами, доступными в C.

в примере (a + b)++

(a + b) вычисляется до некоторого значения и не обязательно является контейнером, который можно использовать снова для работы поверх.

Например, рассмотрим эту

const int a=10; 
a = 5;

подобная ошибка будет возникать здесь,хотя a здесь является контейнером, он бесполезен, потому что это constant и никакие другие операции не допускаются.

0 голосов
/ 18 октября 2018

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

Когда в выражении появляется x++, этооценивается как x и x увеличивается впоследствии.Например, a = 2; b = 2 * (a++); эквивалентно a = 2; b = 2 * a; a = a + 1;.

В вашем примере не удается скомпилировать, поскольку невозможно присвоить значение для a+b.Чтобы быть более явным c=(a+b)++ будет эквивалентно c = (a + b); (a + b) = (a + b) + 1;, что не имеет смысла.

0 голосов
/ 18 октября 2018

В Си операнд ++ должен быть lvalue - местом в памяти.И a, и b являются lvalues, но их сумма не равна, это rvalue .

0 голосов
/ 18 октября 2018

Поскольку оператору ++ требуется ссылка (l-значение), а не значение (r-значение).

i++ увеличит i на 1 и вернет значение i перед увеличением.

, в то время как (a + b)++ не может увеличить значение (a + b), поскольку (a + b) на самом деле не является ссылкой (в памяти, где нужно обновить значение a + b).

...