Question

So i'm reviewing in advanced our upcoming topics and I've come accross lvalues and rvalues, although the definition confuses me. Why is a literal an lvalue?

"rvalue refers to a data value that is stored at some address in memory. An rvalue is an expression that cannot have a value assigned to it"

"The original definition of lvalue referred to "an object that can appear on the left-hand side of an assignment." However, const objects are lvalues, and yet they cannot appear on the left-hand side of an assignment."

Was it helpful?

Solution

There are three categories of non-assignable lvalues in C: const objects, arrays (and objects with members that are const or array) and expressions with incomplete type.

String literals are arrays (by which I mean: the object to which a string literal expression refers is an array). That makes them lvalues.

Informally, an lvalue is an expression that refers to an object, and a string literal is an object.


If you want the formal definition of an lvalue in C, refer to the standard. In C99(6.3.2.1):

An lvalue is an expression with an object type or an incomplete type other than void; if an lvalue does not designate an object when it is evaluated, the behavior is undefined.

with a footnote:

The name ‘‘lvalue’’ comes originally from the assignment expression E1 = E2,in which the left operand E1 is required to be a (modifiable) lvalue. It is perhaps better considered as representing an object ‘‘locator value’’

So appearing on the LHS of an assignment has nothing to do with it, other than the fact that lvalue used to mean something else, in some language other than standard C.

You might think that by that formal definition an integer constant 5 should also be an lvalue expression: it is an expression (specifically a primary-expression), and it has an object type (int is an object type). It's certainly valid to evaluate the expression 5, so if it's an lvalue then it must "designate an object".

This would contradict the definition of the address-of operator, which says that its operand may be an lvalue expression that designates an object. Compilers reject &5, generally with an error message saying that 5 is not an lvalue.

I think the answer lies in 6.5.1, which lists the different types of primary-expression, including constants. For each of the other kinds of primary-expression it says under what conditions it is an lvalue. For constants it conspicuously says nothing, indicating that they aren't lvalues. But usually in the C standard, text of the form "An X is...", with X italicised, is a definition of the term X. So I think the standard could be clearer.

Update: the text in n1570 (a late draft of C11) is, with my emphasis added:

An lvalue is an expression (with an object type other than void) that potentially designates an object

And the equivalent text in C89 (3.2.2.1) says "that designates an object" [thanks hvd]. This suggests to me that the authors of the standard aren't happy with the text either. A constant doesn't potentially designate an object, so under this definition numeric constants certainly are not lvalues.

OTHER TIPS

An informal definition of an lvalue is basically any expression that can refer to an object (in the C sense, anything that takes up memory) such that the object's value may be read or modified. Anything you could potentially apply the unary & operator to is an lvalue.

Unfortunately, you have some expressions that can refer to objects in memory, but the semantics are such that you cannot modify that object's value through that expression. This includes array expressions (including string literals), expressions of const-qualified type, and expressions with incomplete type.

An example of the last type is something like the following:

struct foo;
struct foo *fooptr;

The expression *fooptr is an expression with an incomplete type; struct foo has not yet been fully defined.

So we have modifiable and non-modifiable lvalues. A modifiable lvalue may be the target of an assignment.

String literals are non-modifiable lvalues by virtue of being array type expressions (string literals are stored as arrays of char such that the memory is visible to the entire program, and is held from program startup until termination, and the semantics of arrays are such that array expressions may not be the target of an assignment). This is a distinct situation from numeric literals or individual character constants, which do not refer to items in memory.

rvalues are defined as things that have no name or which you cannot take the address of or temporaries.

The original definition is no longer valid these days. You can take the address of lvalues, but not of rvalues, which for me is the easiest distinction to make.

If you can't take the address of it, then it's an rvalue.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top