Search code examples
cliteralslvaluervalue

rvalue definition is objects that cannot be assigned values, but why are literals lvalues?


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."


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.