Each expression in C (an operator with its arguments, a function call, a constant, a variable name, etc) is characterized by two independent properties: a type and a value category.
Every expression belongs to one of three value categories: lvalue, non-lvalue object (rvalue), and function designator.
Lvalue expression is any expression with object type other than the type void
, which potentially designates an object (the behavior is undefined if an lvalue does not actually designate an object when it is evaluated). In other words, lvalue expression evaluates to the object identity. The name of this value category ("left value") is historic and reflects the use of lvalue expressions as the left-hand operand of the assignment operator in the CPL programming language.
Lvalue expressions can be used in the following lvalue contexts:
If an lvalue expression is used in any context other than sizeof
, _Alignof
, or the operators listed above, non-array lvalues of any complete type undergo lvalue conversion, which models the memory load of the value of the object from its location. Similarly, array lvalues undergo array-to-pointer conversion when used in any context other than sizeof
, _Alignof
, address-of operator, or array initialization from a string literal.
The semantics of const
/volatile
/restrict
-qualifiers and atomic types apply to lvalues only (lvalue conversion strips the qualifiers and removes atomicity).
The following expressions are lvalues:
->
operator *
) operator applied to a pointer to object []
) A modifiable lvalue is any lvalue expression of complete, non-array type which is not const-qualified, and, if it's a struct/union, has no members that are const-qualified, recursively.
Only modifiable lvalue expressions may be used as arguments to increment/decrement, and as left-hand arguments of assignment and compound assignment operators.
Colloquially known as rvalues, non-lvalue object expressions are the expressions of object types that do not designate objects, but rather values that have no object identity or storage location. The address of a non-lvalue object expression cannot be taken.
The following expressions are non-lvalue object expressions:
f().x
, (x,s1).a
, (s1=s2).m
*
operator As a special case, expressions of type void
are assumed to be non-lvalue object expressions that yield a value which has no representation and requires no storage.
Note that a struct/union rvalue that has a member (possibly nested) of array type does in fact designate an object with temporary lifetime. This object can be accessed through lvalue expressions that form by indexing the array member or by indirection through the pointer obtained by array-to-pointer conversion of the array member.
A function designator (the identifier introduced by a function declaration) is an expression of function type. When used in any context other than the address-of operator, sizeof
, and _Alignof
(the last two generate compile errors when applied to functions), the function designator is always converted to a non-lvalue pointer to function. Note that the function-call operator is defined for pointers to functions and not for function designators themselves.
C++ documentation for Value categories |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/c/language/value_category