Expression, lvalue, rvalue

This page was translated by a robot.

An expression designates the link, i.e. a concatenation or nesting of operations. When translating an expression, the compiler must evaluate all operands of the expression in the correct order , process all operators in the correct order and link the operations with one another as required.

The processing of individual operators of an expression results in values ​​that only serve as intermediate results and can be discarded immediately after use. Such values ​​are called rvalues . Other values, however, are permanent: they are stored either in memory or in a processor register reserved for this purpose. Such values ​​are called lvalues ​​and are required by operators that store a value or access the memory address of a value.

Details

In English expressions are called expressions . Each combination of operations that leads to a value is called an expression. Some elements of the C and C++ languages ​​expect an expression as input. This means that operations of any complexity are allowed as input, as long as they result in a value.

In order for the compiler to process operations successfully, each operator specifies what kind of operands it expects and what kind of value it returns. Here, an rvalue designates a value that can result from the evaluation of any expression. An lvalue denotes a value that is stored in a locatable location, that is, that value has a designated place either in memory or in a processor register. Operators can only assign values ​​to localizable values.

The distinction between lvalues ​​and rvalues ​​is often difficult for newcomers to programming and only partially understandable, since it ultimately only matters to the compiler. Sometimes novices stumble upon compiler errors like invalid lvalue without really knowing what the message means. In English, lvalues ​​and rvalues ​​are also referred to as l-value and r-value, but these terms are not used on this page.

The meaning of the two letters L and R has never been standardized, which is why there is some ambiguity to this day. Localizable (L) and Readable (R) are used on this page: localizable and readable. This is for the following reason: In order to be able to evaluate an operand, it must be one thing in particular: Readable. However, in order to assign a value, a location is needed to assign it to. A macro or a constant value, for example, does not need any space, it is firmly integrated in the program, is read out for an operation and then forgotten again. A variable, however, has a place reserved, either in memory or as a processor register. In such a place, an operator can write a value, it can be assigned a location, it has an address.

An lvalue does not always designate a variable, an lvalue can arise from an expression just like an rvalue, but it must explicitly return an lvalue. A typical expression that returns an lvalue is addressing an element of an array or a field of a structvariable. In general, the location locatable by an expression is anywhere in memory, except for variables declared using the registerstorage class.

The C and C++ languages ​​do not always behave in the same way when it comes to lvalues ​​and rvalues. The reason for this lies in the programming of the built-in operators, which has been expanded in some places in C++. The detailed description of the operators always lists what kind of operands an operator expects and what kind of value it returns.

Original explanation: left and right

The two letters L and R originally derive from the consideration of the assignment operator , which always expects an rvalue on the right, which it assigns to an lvalue on the left. So the L stands for left and R for right:

L = R
a = 5;

However, this right-left consideration only applies to the assignment operator, where the expression on the right side must result in a readable value and on the left of the operator there must be an expression whose evaluation results in a localizable value, otherwise the assignment operator cannot assign the value anywhere , since he has no address.

For all other operators, however, this right-left consideration is not correct. For example, there are two variants of the increment: post-increment operator and pre-increment operator . The post variant writes the operator after the operand, the pre variant before it, but both operators expect an lvalue. This is because the operators change this operand themselves, so they must also be able to localize it. This can easily be verified with the following two erroneous lines. Both variants expect an lvalue, although the value is in the second line on the right:

invalid lvalue
invalid lvalue
5++;
++5;

The other way around, there are operators that don't expect any lvalue at all, but two rvalues. For example, the addition operator

no error
5 + 5;

The author recommends remembering only the following: L stands for locatable. Everything else is detail and will hardly ever lead to problems in everyday programming. Even the C11 standard dropped the term rvalue completely in version C11 and instead only speaks of the value of an expression . Over time, the programmer will develop a natural understanding of what is an rvalue and what is an lvalue.

Remarks

An lvalue is always an rvalue: a place that can be located can also be read. However, it should be noted that an lvalue is not the same as writable . For example, evaluating an lvalue can result in a variable that has been constdeclared as . It is also possible that a specification such as privatea variable is not visible at all.

In C++, arguments can be &passed by reference. References are lvalues. Strictly speaking, references are actually the epitome of lvalues, they explicitly indicate addressing.

In modern programming, the concept of lvalues ​​and rvalues ​​has been taken to another level. By programming so-called accessors and mutators , functions are explicitly provided in a class to either only address a variable (access, rvalue) or to offer the possibility of changing it (mutate, lvalue). Here, the accessor is often declared using the const-keyword , whereas the mutator constdoes not have to be-. As a side note, accessors and mutators are not the same as getters and setters.

Some operators expect neither lvalues ​​nor rvalues, but special operands. Below is a table of all operators with details of the expected operands and the return value. Here R stands for rvalue, L for lvalue, S for symbol, A for an argument list and T for a type. The L/R specification means that both lvalues ​​and rvalues ​​can be expected, depending on the operation to be performed. Specifying RCL means that an rvalue is returned in C, but an lvalue in C++.

RValue Operators

LValue Operators

Memory Operators

Type Operators

Special Operators

When calling a function under C, an lvalue is always expected as the first operator. However, since the C language allows function pointers to be written directly, i.e. without dereferencing (syntactic sugar), an rvalue (a function pointer) is also specified here.