473,729 Members | 2,235 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

What exactly is lvalue & rvalue (old c.l.c. posts are all over the map)?

Hi,

Does anyone here have a strong understanding for the meanings of the
terms "lvalue" and "rvalue" as it pertains to C, objects, and different
contexts? If so please share.

I've been reading several old posts/threads on the subject, and they
never end with a conclusion (people keep correcting each other and
disagreeing).

My take on it is that an "lvalue" is an expression that refers to an
object (which can have (a) value(s) within it), and "rvalue" is an
expression that only has a value (ephemeral value as Chris Torek would
claim) and no association with an object.

As far as their use, an "lvalue" that refers to an object of type T,
can be used anwhere an "rvalue" that that has a type T can be, but not
vice versa. So if one uses an lvalue that refers to an int variable in
an context that requires an int value, then simply the value sitting in
the object is dumped into that context.

Is this a fair description?

Nov 14 '05 #1
24 2954
Romeo Colacitti wrote:
Hi,

Does anyone here have a strong understanding for the meanings of the
terms "lvalue" and "rvalue" as it pertains to C, objects, and different contexts? If so please share.

I've been reading several old posts/threads on the subject, and they
never end with a conclusion (people keep correcting each other and
disagreeing).

My take on it is that an "lvalue" is an expression that refers to an
object (which can have (a) value(s) within it), and "rvalue" is an
expression that only has a value (ephemeral value as Chris Torek points out) >and no association with an object.
As far as their use, an "lvalue" that refers to an object of type T,
can be used anwhere an "rvalue" that that has a type T can be, but not vice versa. So if one uses an lvalue that refers to an int variable in an context that requires an int value, then simply the value sitting in the object is dumped into that context.

Is this a fair description?


Both "lvalue" and "(r)value" [current standards prefer to leave out the
'r' and insist that the 'l' means 'locator'] are expressions.

Some expressions are lvalues, while others are rvalues. By "are" I
mean, "evaluate to results that are." "Expression " need not be a full
expression but refers also to subexpressions too (even down to a
token-sequence for a variable name).

Every lvalue is converted to the corresponding (r)value represented in
it's object when used in a context that does not need an object
("value" context), EXCEPT for an lvalue referring to and array object
of type T (it is converted to an (r)value equal to the address of the
first element of the array and of type pointer to T).

When an lvalue is used in an "general object context," then the lvalue
is directly acted upon (no conversion to an rvalue takes place).
Examples are & and sizeof.

There is another special type of "object context" that requires not
only an lvalue, but a MODIFIABLE lvalue. These "special objects
contexts" include expressions involved with ++, --, and the left hand
sides of both = and op= . So only lvalues that are modifiable can be
used here, and they include all lvalues that are NOT: array names,
connected with objects declared as const, or connected with objects of
incomplete type (these are nonmodifiable lvalues).
All other contexts/operators (unless I missed some) require (r)values
as their expressions/operands. For example, arguments in function
calls are expected to be (r)value expressions (but we also lvalues
expressions, but they are automatically converted to the (r)values
represented by their associated objects).
[Another way to say this is, the function call arguments is of "value"
context]

Hope this helps.

Nov 14 '05 #2
Romeo Colacitti wrote:

Hi,

Does anyone here have a strong understanding for the meanings of the
terms "lvalue" and "rvalue" as it pertains to C, objects,
and different contexts? If so please share.

I've been reading several old posts/threads on the subject, and they
never end with a conclusion (people keep correcting each other and
disagreeing).

My take on it is that an "lvalue" is an expression that refers to an
object (which can have (a) value(s) within it), and "rvalue" is an
expression that only has a value (ephemeral value as Chris Torek would
claim) and no association with an object.

As far as their use, an "lvalue" that refers to an object of type T,
can be used anwhere an "rvalue" that that has a type T can be, but not
vice versa.
So if one uses an lvalue that refers to an int variable in
an context that requires an int value,
then simply the value sitting in
the object is dumped into that context.

Is this a fair description?


The lvalue, rvalue distinction
is something that can be determined at compile time.
If you have
int array[1];
then
array[-1] is an example of an lvalue which doesn't refer
to an object. The use of such an lvalue would be undefined behavior.

--
pete
Nov 14 '05 #3
In article <42***********@ mindspring.com>
pete <pf*****@mindsp ring.com> wrote:
The lvalue, rvalue distinction
is something that can be determined at compile time.
Well, in C99, maybe. :-) The C89 definition says, in part, that
if one has a pointer of type "T *":

T *p;

then *p is an lvalue if and only if p actually points to an
object. Thus, in:

p = malloc(sizeof *p);
*p = some_T_value();

"*p" is an lvalue if malloc() succeeded, but not if it failed
(returned NULL).

This is of course a ridiculous situation, which is why the N869
draft wording says that *p is an lvalue in all cases -- even if
p==NULL for instance -- but that the effect is undefined if p does
not point to a valid object of type T.

Unfortunately, the C99 definition is apparently defective as well
(see past discussion here and in comp.std.c).

The terms date back to (at least) Algol, and the intent is clear
enough: lvalues occur on the left side of assignment operators,
and rvalues occur on the right -- hence the names "left value" and
"right value". In languages that lack C's profusion of operators,
a simple definition like this suffices; we write:

a := b;

and there is nothing like "b++" to clutter up the issue. C mixes
everything up into a wonderful, confusing jumble, and even
compiler-writers sometimes get it wrong. :-)
If you have
int array[1];
then
array[-1] is an example of an lvalue which doesn't refer
to an object. The use of such an lvalue would be undefined behavior.


Again, apparently true in C99, but not (technically) in C89. But
this just means the C89 standard has a defect.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #4

Luke Wu wrote:

When an lvalue is used in an "general object context," then the lvalue is directly acted upon (no conversion to an rvalue takes place).
Examples are & and sizeof.


sizeof takes more than lvalues, consider...

sizeof(int *)
sizeof('A')
sizeof(33.029e-3LD)

so are types and constants objects too (note, size of directly taking
the objects as input above, not just lvalues that refer to the objects)
here is another example

sizeof("String Literal")

here, size is receiving only a pointer to the first element of the
string ('S'), so its equivalent to: sizeof(char *)

but that's not what we get, sizeof actually returns the size of the
whole string literal

I don't think sizeof fits cleanly with the theory of lvalues/rvalues.

Nov 14 '05 #5
>Luke Wu wrote:
When an lvalue is used in an "general object context," then the
lvalue is directly acted upon (no conversion to an rvalue takes
place). Examples are & and sizeof.

In article <11************ **********@f14g 2000cwb.googleg roups.com>
Kobu <ko********@gma il.com> wrote:sizeof takes more than lvalues ...
Yes; and it also has more than one syntax:

sizeof expr
sizeof ( type-name )

An expression can, but need not, include outer parentheses; but
to use sizeof on a type-name you must use the parentheses.
consider...

sizeof(int *)
This one requires the parentheses.
sizeof('A')
sizeof(33.02 9e-3LD)
These two do not. (But "e-3LD" is syntactically wrong; I assume
you mean "e-3L", to make it a long-double constant.)
so are types and constants objects too (note, size of directly taking
the objects as input above, not just lvalues that refer to the objects)
No, but they *are* expressions.
here is another example

sizeof("Stri ng Literal")

here, size is receiving only a pointer to the first element of the
string ('S'), so its equivalent to: sizeof(char *)

but that's not what we get, sizeof actually returns the size of the
whole string literal

I don't think sizeof fits cleanly with the theory of lvalues/rvalues.


This is a more interesting case, because of an earlier comp.lang.c
discussion about string literals as initializers:

char s1[] = "this is OK";
char s2[] = ("but this is not");

A string literal -- which is a source code construct, rather than
something you might see at runtime -- can be used as an initializer
for an object of type "array N_opt of char", but if it is to be
used this way, it *must not* be enclosed in parentheses. A number
of compilers allow the parentheses anyway, no doubt because their
parsers have stripped them off by the time the partially-digested
token-sequence is delivered to the part of the compiler front-end
that finishes decorating the parse tree (adjusting types, adding
conversions where implied, and so on).

All of this is something of an aside, though, because given:

char buf[20];

we know that:

sizeof(buf) == sizeof buf

and both arguments to the equality operator are (size_t)20. The
implication here is that, although an array may be surrounded by
parentheses in an expression, it remains an array: it does not
undergo the "degenerati on" or "decay", as some like to call it,
that converts "array N of T" to "pointer to T" merely because it
is parenthesized. (It merely happens that some compilers do this
parentheses-stripping a bit "overzealously" , as it were, so that
the string-literal-as-initializer works even when a diagnostic is
required.)

The whole point of the "object context" vs "value context" that
Luke Wu brings up is to maintain, within the compiler's parse-tree
code, the notion of whether we want to convert array-objects to
pointer-values by computing &arr[0]. (In addition, we must also
remember whether we need to fetch the value of an ordinary object,
so that in:

int a = 3, b = 5;
... any (or no) code that does not change a or b ...
a = b;

we put the value/"rvalue" of b -- 5 -- into the ["lvalue"] object
a, rather than fetching a's previous value of 3, and trying to put
b's value into 3.) Inside the compiler, this context is generally
implicit: we know, based on the operator(s), whether we want to
find the actual *value* of "a" (3, in this case), or simply remember
the *name*:

=
/ \
a b

can be optimized to:

=
/ \
a 5

(because b is still known to be 5), but not to:

=
/ \
3 5

which is nonsensical. This property of "I want a value on the
right, but an object on the left" is associated with the ordinary
assignment operator "=".

Now, there *is* a significant difference between the sizeof and
assignment operators here, in that sizeof permits any expression
of any (legal) type *as well as* an object-name, while "=" demands
*only* an object-name ("lvalue") on the left: "3 = 5;" is an
error, but "sizeof 3" is OK.

All this means is that, in the part of the compiler that deals
with an "=" operator, we have:

/* assume "struct tree *tree" and tree->op is the op, tree->left
is the LHS and tree->right is the RHS, with tree->monad #defined
as either tree->left or tree->right for monadic (unary)
operators */

switch (tree->op) {
...
case ASSIGN:
if (!is_lvalue(tre e->left))
error("assignme nt operator requires an lvalue");
tree->right = rvalue_convert( tree->right, get_typecode(tr ee->left));
/* rvalue_convert produces the error if the conversion is invalid */
break;

while in the code for "sizeof" we have:

case SIZEOF:
typecode = get_typecode(tr ee->monad);
if (is_incomplete_ type(typecode)) /* includes sizeof(void) */
error("sizeof incomplete type");
if (is_function_ty pe(typecode))
error("cannot take size of function");
tree->type = TYPE_SIZE_T;
tree->value = type_size(typec ode) / type_size(TYPE_ CHAR);
tree->is_constant = 1;
/* the division is to get the size in bytes rather than bits */

tree_releasenod e(tree->monad); /* no longer needed */
break;

In other words, we do not need to *check* whether the argument to
sizeof is an object or a value, nor do we have to pass it into the
part of the compiler that extracts an rvalue from an lvalue (which
I called "rvalue_convert " here) if necessary, because all we care
about, in evaluating the "sizeof" operator, is the *type* of the
argument to sizeof. (This is no longer true in C99, where we have
to check whether the argument is a VLA and perhaps generate code
at runtime rather than just marking the result as "is a constant".
But C99 is a much more complicated language than C89.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #6
Chris Torek wrote:
In article <42***********@ mindspring.com>
pete <pf*****@mindsp ring.com> wrote:
The lvalue, rvalue distinction
is something that can be determined at compile time.


Well, in C99, maybe. :-) The C89 definition says, in part, that
if one has a pointer of type "T *":


snipping
If you have
int array[1];
then
array[-1] is an example of an lvalue which doesn't refer
to an object. The use of such an lvalue would be undefined behavior.


Again, apparently true in C99, but not (technically) in C89. But
this just means the C89 standard has a defect.


C99 is worse, because as per the said standard almost every expression
that doesn't resolve to an incomplete types or function type is an
LVALUE. So something like 2+3 is an lvalue in C99. I'll just modify
that errant sentence in the C99, it must obviously be a typo (they
forgot to mention that an lvalue "designates an object.")

Thanks for the help everyone.

Nov 14 '05 #7

pete wrote:
Romeo Colacitti wrote:

/

Is this a fair description?


The lvalue, rvalue distinction
is something that can be determined at compile time.
If you have
int array[1];
then
array[-1] is an example of an lvalue which doesn't refer
to an object. The use of such an lvalue would be undefined behavior.


Yes, "lvalues" and "objects" are not the same thing.

An lvalues are just an expression (or the resolution of an expression)
that is of a form that can normally be used to designate objects (in
your case, array[-1] is of a form that is normally used to designate an
object, but this specific case is not referring to a valid object -
thus undefined behaviour).

Objects can also exist without lvalues . For example,

1)

char *ptr = "Hello";
ptr = NULL;

/* Hereafter the object "Hello" (an array) is lost in our abstract
machine
never to be referred to by an lvalue */

2)

malloc(100);

/* Hereafter the object allocated (100 bytes) is lost, never to be
referred to by an lvalue */


So objects and lvalues are different things.

Nov 14 '05 #8

"Romeo Colacitti" <ww*****@gmail. com> wrote in message
news:11******** **************@ c13g2000cwb.goo glegroups.com.. .
Hi,

Does anyone here have a strong understanding for the meanings of the
terms "lvalue" and "rvalue" as it pertains to C, objects, and different
contexts? If so please share.

I've been reading several old posts/threads on the subject, and they
never end with a conclusion (people keep correcting each other and
disagreeing).


I always thought an lvalue was something you could take the address of using
&.

So an assignment like:

a=b;

could be rewritten as:

*(&a)=b;

if a was a legal lvalue. If you can't then 'a' (whatever it might be) is not
an lvalue.

Bart

Nov 14 '05 #9
Luke Wu wrote:

snip

Yes, "lvalues" and "objects" are not the same thing.

An lvalues are just an expression (or the resolution of an expression) that is of a form that can normally be used to designate objects (in
your case, array[-1] is of a form that is normally used to designate an object, but this specific case is not referring to a valid object -
thus undefined behaviour).

Objects can also exist without lvalues . For example,

1)

char *ptr = "Hello";
ptr = NULL;

Even without reassigning ptr to NULL, there still can never exist an
lvalue that maps to the entire string literal object. The string
literal is an ANONYMOUS object. Pointers can only point to the
independent char object that make up the string literal aggregate array
(object).

/* Hereafter the object "Hello" (an array) is lost in our abstract
machine
never to be referred to by an lvalue */

2)

malloc(100);

The same applies here. Even if you did capture the return value of
malloc (void *) into a pointer with some sort of reference type, you
will still never get an lvalue that suggests the whole 100 byte object
on the heap (it's an ANONYMOUS object).

Although, you can capture the returned (void *) into a pointer to an
array of size equal to 100 bytes, but that is simply a useless case
(the pointer would serve no purpose).

/* Hereafter the object allocated (100 bytes) is lost, never to be
referred to by an lvalue */


So objects and lvalues are different things.


There are normal objects, and anonymous objects.
There are valid lvalues, and invalid lvalues.

Only the former from each sentence above can possibly be part of a
lvalue>object mapping.

Nov 14 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

19
36650
by: Hongzheng Wang | last post by:
In K&R, they said: An object is a named region of storage; an lvalue is an expression refer to an object. How about these concept in C++? `The C++ Programming Language' has a similar explanation, however, it may be too brief. Can anyone give me a more detailed explanation? Or give some referrences
9
3547
by: Steven T. Hatton | last post by:
This is from the draft of the previous version of the Standard: http://www.kuzbass.ru:8086/docs/isocpp/expr.html 2- A literal is a primary expression. Its type depends on its form (lex.literal). A string literal is an *lvalue*; all other literals are *rvalues*. -4- The operator :: followed by an identifier, a qualified-id, or an operator-function-id is a primary-expression. Its type is specified by the
9
3160
by: Kavya | last post by:
These were the questions asked to me by my friend 1. Operator which may require an lvalue operand, yet yield an rvalue. 2. Operator which may require an rvalue operand, yet yield an lvalue. My answer to these questions are & and * respectively. Is/Are there any other operator(s) satisfying these criteria?
6
2352
by: Peter Lee | last post by:
what's the correct behaver about the following code ? ( C++ standard ) I got a very strange result.... class MyClass { public: MyClass(const char* p) { printf("ctor p=%s\n", p);
6
3025
by: Yarco | last post by:
I've alway thought lvalue means Left Value and rvalue means Right Value before i've read someone's article. It is said "lvalue = location value" and "rvalue = read value". Which one is right, then?
9
3336
by: usao | last post by:
Does anyone have an example of how to create a class which describes and array, such that I can use the subscript operator on both the left and right side of an assignment statement? This is as close as I can get, but I feel it's kludgey and slow... #include <iostream.h> template<class T> class foo { T *data;
2
1768
by: Chad | last post by:
The following question actually stems from an old Chris Torek post. And I quote from the following old CLC url http://groups.google.com/group/comp.lang.c/browse_thread/thread/ce93f8bf3e61aede/cfeed3fda1d0ee46?hl=en&lnk=gst&q=convert+lvalue+to+rvalue#cfeed3fda1d0ee46 "Mathematically speaking, unary `&' and `*' are inverse functions. Unary `&' takes an lvalue of type `T' and produces an rvalue of type `pointer to T'; unary `*' takes an...
0
8913
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8761
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9426
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9280
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9200
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9142
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8144
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
6016
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4525
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.