lvalue required as left operand of assignment c что это

Понимание lvalue и rvalue в C и С++

Привет, Хабр! Представляю вашему вниманию перевод статьи Eli Bendersky, Understanding of lvalues and rvalues in C and C++.

От переводчика: предлагаю Вашему вниманию перевод интересной статьи об lvalue и rvalue в языках C/C++. Тема не нова, но знать об этих понятиях никогда не поздно. Статья рассчитана на новичков, либо на программистов переходящих с C (или других языков) на C++. Поэтому будьте готовы к подробному разжёвыванию. Если вам интересно, добро пожаловать под кат

Термины lvalue и rvalue не являются чем-то таким, с чем часто приходится сталкиваться при программировании на C/C++, а при встрече не сразу становится ясным, что именно они означают. Наиболее вероятное место столкнуться с ними — это сообщения компилятора. Например, при компиляции следующего кода компилятором gcc :

Вы уведите нечто следующее:

Согласен, что этот код немного надуманный, и вряд ли Вы будете писать нечто подобное, однако сообщение об ошибке упоминает lvalue — термин, который не так часто увидишь в туториалах по C/C++. Другой пример нагляден при компиляции следующего кода при помощи g++ :

Вы увидите следующую ошибку:

Опять же, в сообщение об ошибке упоминается мистическое rvalue. Что же в C и C++ понимается под lvalue и rvalue? Это и есть тема данной статьи.

Простое определение

Для начала нарочито дадим определения lvalue и rvalue в упрощённой форме. В дальнейшем эти понятия будут рассмотрены под увеличительным стеклом.

lvalue (locator value) представляет собой объект, который занимает идентифицируемое место в памяти (например, имеет адрес).

rvalue определено путём исключения, говоря, что любое выражение является либо lvalue, либо rvalue. Таким образом из определения lvalue следует, что rvalue — это выражение, которое не представляет собой объект, который занимает идентифицируемое место в памяти.

Элементарные примеры

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

Оператор присваивания ожидает lvalue с левой стороны, и var является lvalue, потому что это объект с идентифицируемым местом в памяти. С другой стороны, следующие заклинания приведут к ошибкам:

Однако, не все присваивания результату вызова функции ошибочны. Например, использование ссылок в C++ делает это возможным:

Здесь foo возвращает ссылку, которая является lvalue, то есть ей можно придать значение. Вообще, в C++ возможность возвращать lvalue, как результат вызова функции, существенна для реализации некоторых перегруженных операторов. Как пример приведём перегрузку оператора [] в классах, которые реализуют доступ по результатам поиска. Например std::map :

Присваивание mymap[10] работает, потому что неконстантная перегрузка std::map::operator[] возвращает ссылку, которой может быть присвоено значение.

Изменяемые lvalue

Таким образом не всем lvalue можно присвоить значение. Те, которым можно, называются изменяемые lvalue (modifiable lvalues). Формально C99 стандарт определяет изменяемые lvalue как:

Преобразования между lvalue и rvalue

Образно говоря, конструкции языка, оперирующие значениями объектов, требуют rvalue в качестве аргументов. Например, бинарный оператор ‘+’ принимает два rvalue в качестве аргументов и возвращает также rvalue:

Как мы уже видели раньше, a и b оба lvalue. Поэтому в третьей строке они подвергаются неявному преобразованию lvalue-в-rvalue. Все lvalue, которые не являются массивом, функцией и не имеют неполный тип, могут быть преобразованы в rvalue.

Что насчёт преобразования в другую сторону? Можно ли преобразовать rvalue в lvalue? Конечно нет! Это бы нарушило суть lvalue, согласно его определению (Отсутствие неявного преобразования означает, что rvalue не могут быть использованы там, где ожидается lvalue).

Это не означает, что lvalue не могут быть получены из rvalue явным способом. Например, унарный оператор ‘*’ (разыменование) принимает rvalue в качестве аргумента, но возвращает lvalue в качестве результата. Рассмотрим следующий верный код:

Обратно, унарный оператор ‘&’ (адрес) принимает lvalue как аргумент и производит rvalue:

Символ «&» играет несколько другую роль в C++ — он позволяет определить ссылочный тип. Его называют «ссылкой на lvalue». Неконстантной ссылке на lvalue не может быть присвоено rvalue, так как это потребовало бы неверное rvalue-в-lvalue преобразование:

Константным ссылкам на lvalue можно присвоить rvalue. Так как они константы, значение не может быть изменено по ссылке и поэтому проблема модификации rvalue просто отсутствует. Это свойство делает возможным одну из основополагающих идиом C++ — допуск значений по константной ссылке в качестве аргументов функций, что позволяет избежать необязательного копирования и создания временных объектов.

CV-специфицированные rvalues

lvalue (3.10) на тип T, не являющимся функциональным, или массивом, может быть преобразован в rvalue. [. ] Если T не класс, типом rvalue является cv-неспецифицированная версия типа T. Иначе, типом rvalue является T.

Так что же значит «cv-неспецифицированный»? CV-спецификатор — это термин, используемый для описания const и volatile спецификаторов типа.

Каждый тип, который является cv-неспецифицированным полным или неполным объектным типом или типом void (3.9), имеет соответственно три cv-специфицированные версии: тип со спецификатором const, тип со спецификатором volatile и тип со спецификаторами const volatile. [. ] CV-специфицированные и cv-неспецифицированные типы являются различными, однако они имеют одинаковое представление и требования по выравниванию.

Ссылки на rvalue (C++11)

Ссылки на rvalue и сопутствующий концепт семантики переноса являются одним из наиболее мощным инструментом, добавленным в язык C++11. Подробная дискуссия на эту тему выходит за рамки этой скромной статьи (вы можете найти кучу материала, просто погуглив «rvalue references». Вот некоторые ресурсы, которые я нахожу полезными: этот, этот и особенно вот этот), но всё же я хотел бы привести простой пример, потому что считаю, что данная глава является наиболее подходящим место, чтобы продемонстрировать как понимание lvalue и rvalue расширяет наши возможности рассуждать о нетривиальных концепциях языка.

Добрая половина статьи была потрачена на объяснение того, что одним из самых главных различий между lvalue и rvalue является тот факт, что lvalue можно изменять, в то время как rvalue — нет. Что же, C++11 добавляет одну важнейшую характерную особенность в этом различии, разрешая нам иметь ссылки на rvalue и тем самым изменять их в некоторых случаях.

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

Давайте запустим простой код, который копирует содержимое v1 в v2 :

И вот, что мы увидим:

Что совершенно логично, так как это точно отражает, что происходит внутри оператора присваивания. Но давайте предположим, что мы хотим присвоить v2 некоторое rvalue:

Хотя здесь я только присваиваю значение свеже созданному вектору, это является одной из демонстраций общего случая, когда некоторое временное rvalue создаётся и присваивается v2 (это может случится например, если функция возвращает вектор). Вот что мы увидим на экране:

Ого! Выглядит очень хлопотно. В частности, здесь потребовалась дополнительная пара вызовов конструктора с деструктором, чтобы создать, а потом удалить временный объект. И это печально, так как внутри копирующего оператора присваивания другой временный объект создаётся и удаляется. Дополнительная работа за зря.

Но, нет! C++11 даёт нам ссылки на rvalue, с помощью которых можно реализовать «семантику переноса», а в частности «переносящий оператор присваивания» (теперь понятно почему я всё время называл operator= копирующим оператором присваивания. В C++11 эта разница становится важной). Давайте добавим другой operator= в IntVec :

Двойной асперсанд — это ссылка на rvalue. Он означает как раз то, что и обещает — даёт ссылку на rvalue, который будет уничтожен после вызова. Мы можем использовать этот факт, чтобы просто «стащить» внутренности rvalue — они ему всё равно не нужны! Вот, что выведется на экран:

Хочу только отметить ещё раз, что этот пример только вершина айсберга семантики переноса и ссылок на rvalue. Как вы можете догадаться, это сложная тема с множеством частных случаев и загадок. Я пытался лишь продемонстрировать очень интересное применение различий между lvalue и rvalue в C++. Компилятор очевидно может их различать и позаботится о вызове правильного конструктора во время компиляции.

Заключение

Можно написать много C++ кода, не задумываясь о разногласиях rvalue и lvalue, опуская их как непонятный жаргон компилятора в сообщениях об ошибках. Однако, как я пытался показать в этой статье, лучшее владение этой темы обеспечит более глубокое понимание определённых конструкций C++, и сделает части стандарта C++ и дискуссии между экспертами языка для вас более доступными.

В стандарте C++11 эта тема является ещё более важной, так как C++11 вводит понятия ссылок на rvalue и семантики переноса. Чтобы действительно понять новые особенности языка, строгое понимание rvalue и lvalue просто необходимо.

Источник

Solve error: lvalue required as left operand of assignment

In this tutorial you will know about one of the most occurred error in C and C++ programming, i.e. lvalue required as left operand of assignment.

lvalue means left side value. Particularly it is left side value of an assignment operator.

rvalue means right side value. Particularly it is right side value or expression of an assignment operator.

Example:

In above example a is lvalue and b + 5 is rvalue.

Solve error: lvalue required as left operand of assignment

Now let see some cases where this error occur with code.

Example 1:

When you will try to run above code, you will get following error.

Solution: In if condition change assignment operator to comparison operator, as shown below.

Example 2:

Above code will show the error: lvalue required as left operand of assignment operator.

Here problem occurred due to wrong handling of short hand operator (*=) in findFact() function.

Solution: Just by changing the line ans*i=ans to ans*=i we can avoid that error. Here short hand operator expands like this, ans=ans*i. Here left side some variable is there to store result. But in our program ans*i is at left hand side. It’s an expression which produces some result. While using assignment operator we can’t use an expression as lvalue.

The correct code is shown below.

Example 3:

Above code will show the same lvalue required error.

Reason and Solution: Ternary operator produces some result, it never assign values inside operation. It is same as a function which has return type. So there should be something to be assigned but unlike inside operator.

The correct code is given below.

Some Precautions To Avoid This Error

There are no particular precautions for this. Just look into your code where problem occurred, like some above cases and modify the code according to that.

Mostly 90% of this error occurs when we do mistake in comparison and assignment operations. When using pointers also we should careful about this error. And there are some rare reasons like short hand operators and ternary operators like above mentioned. We can easily rectify this error by finding the line number in compiler, where it shows error: lvalue required as left operand of assignment.

Programming Assignment Help on Assigncode.com, that provides homework ecxellence in every technical assignment.

Comment below if you have any queries related to above tutorial.

Источник

Ошибка Lvalue required

Пожалуйста помогите исправить ошибку Lvalue required в этой строке: str2=+(s[k-1]);

Ошибка: (19,22): Lvalue required
Пожалуйста помогите найти ошибку! Ошибка: (19,22):Lvalue required Задача несложная, но не как не.

lvalue required as left operand of assignment c что этоИсправить код: ошибка компиляции lvalue required
#include #include #include main ()< int n,m,t ; float.

Я не смотрел ваш код, но приведенное вами предложение

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

Грубо говоря, если есть массив

то просто имя массива (т.е. конструкция «a») внутри выражения трактуется как

т.е. берётся адрес самого первого элемента массива и приводится к указателю на тип, который получается, если выкинуть старшее измерение. В нашем случае это будет указатель на < массив из 20 int'ов >. Таким образом, конструкция «a + 3» для данного массива вполне законная и является указателем на элемент a[3][0], приведённом к типу < массив из 20 int'ов >. Т.е. фактически мы получим в результате < массив из 20 int'ов >, который можно подать, например, в процедуру, описанную как

трактуется как тот же самый адрес, а каждая индексация преобразуется в поинтерную арифметику с последующим разыменованием указателя

Источник

compiling c code: error: lvalue required as left operand of assignment

When I try to compile some code on gcc 4.4.5, gcc runs into an error on this line:

These 2 macros are defined as:

I did not have a problem compiling this on solaris with gcc 3.4.5.

I’ve been trying to figure out why it won’t compile for quite a while but to no avail. Can anyone point me in the right direction?

ODATA and DDATA are defined as:

lvalue required as left operand of assignment c что это

3 Answers 3

I find it hard to believe you could compile it on Solaris. The left-hand side of your assignment is a result of a cast. The results of casts in C language are always rvalues. You can’t assign anything to an rvalue. It simple makes no sense. Rvalues are not objects. They are not stored in memory, which is why trying to assign anything to an rvalue makes no sense. This is a very fundamental fact of C, which is why I can’t believe you could compile it with any C compiler.

For example, this code

does not compile for the very same reason your code does not compile.

It is hard to «point you in the right direction» because it is totally not clear what you were trying to do. What is that assignment supposed to mean? Why do you want to have casts on both sides of the assignment?

Your ODATA() and DDATA() macros evaluate to lvalues (the cast in those macros is to a pointer that’s dereferenced to obtain the lvalue). So what needs figuring out is what the original ORG() and DEST() macros do:

Basically they take the lvalues produced by the ODATA() and DDATA() macros and treat them as pointers. GCC 3.4.5’s cast-as-lvalue language extension, which was deprecated in 3.4.5 and removed in 4.0, allows the result of a cast to be used as an lvalue if the operand to the cast is an lvalue. We can emulate that by performing our own pointer/address manipulation and dereferencing. Change the ORG() and DEST() macros to take the address of the lvalues produced by the ODATA() and DDATA() macros, then dereference that address as a pointer to the desired type. This should produce equivalent results in GCC 4.x as you were getting in GCC 3.4.5 with your existing macros:

The result of a cast is an rvalue, not an lvalue. IOW, the result is just the «raw» value, not the original object that was the source of the value.

It’s not entirely apparent how to fix things in your case. In particular, without knowing what the ODATA(e) and DDATA(e) are/do, it’s hard to guess how to proceed from there.

If you’re trying to assign one struct to another, you can do something like:

Edit: okay, after the macros are expanded, we end up with something like this:

To make a long story short, this looks like a fairly serious case of reverse engineering, and it’s almost impossible to predict how much code will need to be examined and understood before you can rewrite/update it to the point that you’ll get the right result from a modern compiler.

Источник

lvalue and rvalue assignment error [duplicate]

Why is the above code giving me an error, the specific error I get is

lvalue required as left operand of assignment.

9 Answers 9

now x+1=y will throw lvalue required which means left hand side of = should be a variable not a constant

lvalue required as left operand of assignment c что это

The result of the postincrement operator is a temporary object that has the value before incrementing. You may not assign a temporary object. So this statement is invalid.

You could rewrite it the following way

The statement above is correct.

x++ cannot be use as left operand because it returns a value, not an address.

x++ is r-value, and you cannot assign to it, you can rewrite it as follows: 3 = 5; which makes no sense, you cannot assign 5 to 3.

lvalue required as left operand of assignment c что это

lvalue required as left operand of assignment c что это

To achieve what you want, you need to do:

In C++11, with its new sequencing rules, you could also do:

From my understanding the above code should theoretically copy over the value of y into x, then finally increment the value of x after the copy has finished.

x++ evaluates to an r-value (constant). Assignment operator = needs an l-value (variable) as its left operand.

you can’t assign a constant to a constant. x++ = y is not a valid statement in either of C or C++.

lvalue required as left operand of assignment c что это

x++ results in a temporary object that has x value before the increment. And you cannot assign a temp object.

Examples for clarification:

lvalue required as left operand of assignment c что это

The core issue is this:

From my understanding the above code should theoretically copy over the value of y into x, then finally increment the value of x after the copy has finished. So it would print out «6».

In fact, the sequencing of the increment is undefined. As in, it is completely undefined as to when x is incremented, except that it must occur before some specific times. Reading or writing x during this period of undefined value is undefined behaviour. That’s why x++ does not return x (an lvalue you can write to) but an rvalue you cannot write to- because there’s simply nothing useful you can do with x until the time it’s guaranteed to be incremented (except take the address, maybe).

You can still break this rule by referring to x twice- for example, consider:

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *