469,904 Members | 2,081 Online

# r- r-value vs l-value?

Can someone please explain what this means and illustrate the
difference with some code.

Thanks,
Zach

Jun 5 '06 #1
40 9443
Zach <ne****@gmail.com> wrote:
Can someone please explain what this means and illustrate the
difference with some code.

Sure. An l-value is an expression that may legally appear on the left-
hand side of the assignment operator, =. An r-value is an expression
that may appear on the right-hand side. The set of r-values is a subset
of the the set of l-values. For example, given:

int a;
int b[50];

The following are l-values (and also r-values):

a
b[10]

Whereas the following are ONLY r-values:

17
a + 5
b

Therefore, the following line of code will fail to compile:

a + 5 = 15;

Hope that helps,

--
Chris Smith - Lead Software Developer / Technical Trainer
MindIQ Corporation
Jun 5 '06 #2
Chris Smith said:
Zach <ne****@gmail.com> wrote:
Can someone please explain what this means and illustrate the
difference with some code.
Sure. An l-value is an expression that may legally appear on the left-
hand side of the assignment operator, =.

More formally, "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 behaviour is undefined."

An r-value is an expression that may appear on the right-hand side. The set of r-values is a subset
of the the set of l-values. For example, given:

int a;
int b[50];

The following are l-values (and also r-values):

a
b[10]

Whereas the following are ONLY r-values:

17
a + 5
b

Strictly speaking, b is an lvalue, but not a modifiable lvalue. Section
6.3.2.1(1) - which I quoted above - goes on to say: "A modifiable lvalue is
an lvalue that does not have array type, does not have an incomplete type,
does not have a const-qualified type, and if it is a structure or union,
does not have any member (including, recursively, any member or element of
all contained aggregates or unions) with a const-qualified type."

<snip>

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jun 5 '06 #3
Richard Heathfield <in*****@invalid.invalid> wrote:
Strictly speaking, b is an lvalue, but not a modifiable lvalue. Section
6.3.2.1(1) - which I quoted above - goes on to say: "A modifiable lvalue is
an lvalue that does not have array type, does not have an incomplete type,
does not have a const-qualified type, and if it is a structure or union,
does not have any member (including, recursively, any member or element of
all contained aggregates or unions) with a const-qualified type."

Interesting... is there a situation in legal code where this makes a
difference?

--
Chris Smith - Lead Software Developer / Technical Trainer
MindIQ Corporation
Jun 5 '06 #4
Chris Smith wrote:

Sure. An l-value is an expression that may legally appear on the left-
hand side of the assignment operator, =. An r-value is an expression
that may appear on the right-hand side. The set of r-values is a subset
of the the set of l-values. For example, given:

int a;
int b[50];

The following are l-values (and also r-values):

a
b[10]

Whereas the following are ONLY r-values:

17
a + 5
b

Therefore, the following line of code will fail to compile:

a + 5 = 15;

Hope that helps,

Where are the rules of what may go on each side?

Zach

Jun 5 '06 #5
Chris Smith wrote:

Richard Heathfield <in*****@invalid.invalid> wrote:
Strictly speaking, b is an lvalue,
but not a modifiable lvalue. Section
6.3.2.1(1) - which I quoted above - goes on to say:
"A modifiable lvalue is
an lvalue that does not have array type,
does not have an incomplete type,
does not have a const-qualified type,
and if it is a structure or union,
does not have any member (including, recursively,
any member or element of
all contained aggregates or unions) with a const-qualified type."

Interesting... is there a situation in legal code where this makes a
difference?

If (b) was not an lvalue,
then (&b) would be undefined.

--
pete
Jun 5 '06 #6
In article <44***********@mindspring.com>,
pete <pf*****@mindspring.com> wrote:
Chris Smith wrote:
Richard Heathfield <in*****@invalid.invalid> wrote:
> Strictly speaking, b is an lvalue,
> but not a modifiable lvalue.
Interesting... is there a situation in legal code where this makes a
difference?

If (b) was not an lvalue,
then (&b) would be undefined.

I believe Richard and Chris are talking about lvalue as compared
to "modifiable lvalue".
--
"law -- it's a commodity"
-- Andrew Ryan (The Globe and Mail, 2005/11/26)
Jun 5 '06 #7
Richard Heathfield <in*****@invalid.invalid> writes:
Chris Smith said:
Zach <ne****@gmail.com> wrote:
Can someone please explain what this means and illustrate the
difference with some code.

Sure. An l-value is an expression that may legally appear on the left-
hand side of the assignment operator, =.

More formally, "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 behaviour is undefined."

[...]

Which, as I've argued before, is a poor definition.

The C90 standard's definition is:

An _lvalue_ is an expression (with an object type or an incomplete
type other than void) that designates an object.

The problem with this is that, if it's interpreted literally, certain
expressions are or are not lvalues depending on their current values.
For exmaple if p is a pointer to int that currently points to an int
object, then *p is clearly an lvalue -- but if p == NULL, then *p
doesn't currently designate an object. Since lvalueness determines
compile-time legality, this clearly wasn't the intent.

The C99 standard's definition, which Richard quoted above, was
intended to correct this problem -- and it did, but at the expense of
introducing another one. Designating an object is what lvalueness is
all about; the C99 definition lost this. For example, 42 is "an
expression with an object type ...", so, if the definition is to be
taken literally, 42 is an lvalue. And since it doesn't designate an
object, evaluating 42 invokes undefined behavior. Again, this clearly
isn't what was intended.

What the definition *should* say is that an lvalue is an expression
with an object type or an incomplete type other than void that
designates or *potentially* designates an object. For example, *p
potentially designates an object, depending on the current value of p,
but *p is an lvalue regardless of the value of p. C99's statement
that "if an lvalue does not designate an object when it is evaluated,
the behaviour is undefined" is then valid. The problem is defining
the phrase "potentially designates" (or some equivalent phrase) in
standardese.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 5 '06 #8
On 2006-06-05 03:55, Zach wrote:
Chris Smith wrote:

Sure. An l-value is an expression that may legally appear on the left-
hand side of the assignment operator, =. An r-value is an expression
that may appear on the right-hand side. The set of r-values is a subset
of the the set of l-values. For example, given:

int a;
int b[50];

The following are l-values (and also r-values):

a
b[10]

Whereas the following are ONLY r-values:

17
a + 5
b

Therefore, the following line of code will fail to compile:

a + 5 = 15;

Hope that helps,

Where are the rules of what may go on each side?

A nice rule is "when it makes sense". An l-value is something you can
(after evaluation) assign a value to and an r-value is a value (again,
after evaluation) that can be assigned. Generally speaking this means
that an l-value evaluates to a variable (or and index into an array)
while an r-value evaluates to a value of the same type as the l-value.

Erik Wikström
--
"I have always wished for my computer to be as easy to use as my
telephone; my wish has come true because I can no longer figure
out how to use my telephone" -- Bjarne Stroustrup
Jun 5 '06 #9

L-value -> something u can store to -> mem location
R-value -> something u can read from -> variable
you cant store to (a+5) , if a is int
but you can store to *(a+5), where a is int*

Onkar
Erik Wikström wrote:
On 2006-06-05 03:55, Zach wrote:
Chris Smith wrote:

Sure. An l-value is an expression that may legally appear on the left-
hand side of the assignment operator, =. An r-value is an expression
that may appear on the right-hand side. The set of r-values is a subset
of the the set of l-values. For example, given:

int a;
int b[50];

The following are l-values (and also r-values):

a
b[10]

Whereas the following are ONLY r-values:

17
a + 5
b

Therefore, the following line of code will fail to compile:

a + 5 = 15;

Hope that helps,

Where are the rules of what may go on each side?

A nice rule is "when it makes sense". An l-value is something you can
(after evaluation) assign a value to and an r-value is a value (again,
after evaluation) that can be assigned. Generally speaking this means
that an l-value evaluates to a variable (or and index into an array)
while an r-value evaluates to a value of the same type as the l-value.

Erik Wikström
--
"I have always wished for my computer to be as easy to use as my
telephone; my wish has come true because I can no longer figure
out how to use my telephone" -- Bjarne Stroustrup

Jun 5 '06 #10
On 2006-06-05 13:08, onkar wrote:
L-value -> something u can store to -> mem location
R-value -> something u can read from -> variable

I'd say R-value -> something with a value -> variable, constant, etc.

Erik Wikström
--
"I have always wished for my computer to be as easy to use as my
telephone; my wish has come true because I can no longer figure
out how to use my telephone" -- Bjarne Stroustrup
Jun 5 '06 #11
Erik Wikström wrote:
On 2006-06-05 13:08, onkar wrote:
L-value -> something u can store to -> mem location
R-value -> something u can read from -> variable

I'd say R-value -> something with a value -> variable, constant, etc.

Variables are typically lvalues, not rvalues though lvalues can be
converted to rvalues as needed. Constants, indeed, are rvalues and can
never be lvalues in C.

Jun 5 '06 #12
Zach wrote:
Can someone please explain what this means and illustrate the
difference with some code.

Thanks,
Zach
An lvalue is an expression that refers to an object (a region of
memory) in such a way that the object may be read or modified. An
rvalue is an expression that is not an lvalue.

Only lvalues may appear on the left-hand side of an assignment
expression, but not all lvalues may be writable.
From Harbison & Steele, 5th ed., the following expressions may be

lvalues, provided they do not have the type "array of ..." :

e // e must be a variable name
e[k]
(e) // e must be an lvalue
e.name // e must be an lvalue
e->name
*e
string-constant

The following expressions may *not* be lvalues:

array names
functions
enumeration constants
assignment expressions
casts
function calls

Jun 5 '06 #13
Erik Wikström <Er***********@telia.com> writes:
On 2006-06-05 13:08, onkar wrote:
L-value -> something u can store to -> mem location
R-value -> something u can read from -> variable

I'd say R-value -> something with a value -> variable, constant, etc.

The C standard doesn't use the term "rvalue" except in one 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". What is sometimes called
"rvalue" is in this International Standard described as the "value
of an expression".

An lvalue is an expression that designates an object, or that can
designate an object. (The latter is necessary to cover cases like
"*ptr", where ptr is a pointer to some object type; it may or may not
actually designate an object depending on its current value, but it's
an lvalue regardless.) (The C90 standard's definition of lvalue was
flawed; the C99 standard's correction just made it worse.)

An rvalue, if you insist on using the term, is simply the value of an
expression.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 5 '06 #14
John Bode <jo*******@my-deja.com> wrote:
From Harbison & Steele, 5th ed., the following expressions may be

lvalues, provided they do not have the type "array of ..." :

e // e must be a variable name
e[k]
(e) // e must be an lvalue
e.name // e must be an lvalue
e->name
*e
string-constant

The following expressions may *not* be lvalues:

array names
functions
enumeration constants
assignment expressions
casts
function calls

Array names? Isn't that the same mistake I made a bit earlier?

--
Chris Smith - Lead Software Developer / Technical Trainer
MindIQ Corporation
Jun 5 '06 #15

Chris Smith wrote:
John Bode <jo*******@my-deja.com> wrote:
From Harbison & Steele, 5th ed., the following expressions may be

lvalues, provided they do not have the type "array of ..." :

e // e must be a variable name
e[k]
(e) // e must be an lvalue
e.name // e must be an lvalue
e->name
*e
string-constant

The following expressions may *not* be lvalues:

array names
functions
enumeration constants
assignment expressions
casts
function calls

Array names? Isn't that the same mistake I made a bit earlier?

Mr.Chris, will you please explain how array names can be an l-value?

Jun 5 '06 #16
"John Bode" <jo*******@my-deja.com> writes:
Zach wrote:
Can someone please explain what this means and illustrate the
difference with some code.

An lvalue is an expression that refers to an object (a region of
memory) in such a way that the object may be read or modified. An
rvalue is an expression that is not an lvalue.

The origin of the terms is that an "lvalue" can appear on the left
hand side of an assignment, and an "rvalue" can appear on the right
hand side of an assignment. Given this:

int x, y;
x = y;

y is clearly an lvalue (since it refers to an object), but it's also
an rvalue (it appears on the RHS of the assignment).

This kind of confusion is probably why the standard doesn't use the
term "rvalue" (except in passing in a single footnote).

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 5 '06 #17

Chris Smith wrote:
John Bode <jo*******@my-deja.com> wrote:
From Harbison & Steele, 5th ed., the following expressions may be

lvalues, provided they do not have the type "array of ..." :

e // e must be a variable name
e[k]
(e) // e must be an lvalue
e.name // e must be an lvalue
e->name
*e
string-constant

The following expressions may *not* be lvalues:

array names
functions
enumeration constants
assignment expressions
casts
function calls

Array names? Isn't that the same mistake I made a bit earlier?

H&S appear to be a little inconsistent on this point. In one paragraph
they seem to consider arrays to be non-modifiable lvalues, but in the
table they explicitly claim that array names may not be lvalues. My
initial guess is that the second table would be expressions that could
not be *modifiable* lvalues.

Jun 5 '06 #18
muttaa <as***********@gmail.com> wrote:
Mr.Chris, will you please explain how array names can be an l-value?

It's a substantial portion of the rest of this thread. Apparently, the
C standard considers array names to be "unmodifiable lvalues" instead of
considering them not to be lvalues at all. Pete pointed out earlier in
the thread that this is an observable distinction because given an array
declared as "int b[10]" it is legal to ask for (&b), which is only
possible for an lvalue.

Note that in this way, the C standard's definition of lvalue is not
identical to common concept of lvalues in general programming languages,
which is that the expression may appear on the left-hand side of an
assignment operator. Clearly an array name is not an lvalue in the
classical sense. Specifications define their own language, and the C
standard chooses to define lvalue in one way, whereas it is commonly
used in other ways in practice.

--
Chris Smith - Lead Software Developer / Technical Trainer
MindIQ Corporation
Jun 5 '06 #19
Zach wrote:
Chris Smith wrote:

Sure. An l-value is an expression that may legally appear on the left-
hand side of the assignment operator, =. An r-value is an expression
that may appear on the right-hand side. The set of r-values is a subset
of the the set of l-values. For example, given:

int a;
int b[50];

The following are l-values (and also r-values):

a
b[10]

Whereas the following are ONLY r-values:

17
a + 5
b

Therefore, the following line of code will fail to compile:

a + 5 = 15;

Hope that helps,
Where are the rules of what may go on each side?

Since there is a lot of confusion in that discussion, I'll give rules
(based on C++).
First, I'll correct statements of Chris Smith:
int a;
int b[50];
a is an lvalue
b[10] is an lvalue
17 is an rvalue
a+5 is an rvalue
b *is an lvalue*

An lvalue designate an object (it may designate an inexistent or
invalid object), while an rvalue is a value itself...
In some sense, an lvalue is not a value, it is an object...

lvalues are not rvalues and rvalues are not lvalues... They are totally
different concepts.

Expressions can be rvalues or lvalues and take parameters... And
specific values are expected as arguments.
That is : there are three different contexts where an expression can
appear.
1) A context expecting an rvalue.
2) A context expecting an lvalue.
3) A context accepting both an rvalue or an lvalue (in that case,
semantics are slightly different depending on the type of the
expression).
This third category mainly exists in C++.

Any expression is either an lvalue or an rvalue.
If an lvalue-expression is found in a context where an rvalue is
expected, an rvalue-to-lvalue conversion occurs (and this conversion is
not conceptual... Physical things occur... And HERE can happen
segmentation faults).

If an rvalue is found in a context where an lvalue is expected, the
program is ill-formed.

Now, we can give the rule (C++ rules without operator overloading, but
AFAIK they are the same in C, except where I specify it explicitly).

string literals are lvalues. Other literals are rvalues.
An identifier identifying a variable (automatic or static, const or
not, volatile or not), or a function (yes) is an lvalue.
Additive (+ -), multiplicative (* / %), shift (<< >>), relationals (<
<= >= >), equality (== !=), bitwise (| & ^) and logical (|| &&)
operators expect rvalues operands and yields rvalues.

Postfix increment and decrement operators expect lvalues and yield
rvalues.

Assignment operators (= += *= etc) take a left lvalue operand and
expect a right rvalue operand and yield a rvalue in C, and an lvalue in
C++ (this is an incompatibility issue between C and C++).

Unary * operator :
It expects an rvalue operand and yields an lvalue which designates the
object pointed-to by the pointer.
The type can be incomplete, as far as this expression doesn't get an
lvalue-to-rvalue conversion.
The pointer can be NULL, as far as the expression doesn't get an
lvalue-to-rvalue conversion.

Unary & operator :
Expects an lvalue operand and yields an rvalue.

Arguments of functions expect rvalues (except if the parameter is a
reference type in C++)... What means that lvalue-to-rvalues conversion
occur if arguments are lvalues.

Function calls are rvalues (except if the returned type is a reference
type in C++).

Comma operator: It doesn't expect any particular type of value (i.e. it
accepts both lvalues and rvalues with different semantics).
The left operand can be either an rvalue or an lvalue, and is
discarded. If it is an lvalue, there is *no* lvalue-to-rvalue (nor
array-to-pointer, not function-to-pointer) conversion. In particular,
if p is a NULL pointer (*p , another_valid_expression) is valid and has
a well-defined behavior.
The right operand can either be an rvalue or an lvalue.
In C++, the resulting expression is an lvalue if (and only if) the
right operand is an lvalue, and has the same value than the right
operand, or is an rvalue if (and only if) the right operand is an
rvalue.
In C, AFAIK, the left operand can be either an rvalue or an lvalue and
the value is discarded (as in C++), but the right operand is expected
to be an rvalue, and the expression yields an rvalue.

Prefix increment and decrement operators are equivalent to +=1 and -=1
Thus, in C, they expect lvalue operands and yield rvalues, while in
C++, they expect lvalue operands and yield lvalues.

The dot operator (member access) for non-static data members (in C all
members are non-static data members) can accept an rvalue or an lvalue
(even in C, this operator enters in the third category).
If the operand is an lvalue, the expression is an lvalue.
If the operand is an rvalue, the expression is an rvalue.

p[i] is equivalent to *(p + i) and thus, expect rvalue operands, and
yield an lvalue.
Similarly p->member is equivalent to (*p).member and expect an rvalue
operand and yield an lvalue.

conditional expressions (aka the ?: ternary operator) has also
different meanings in C and C++
It expects an rvalue as first operand (converted to bool in C++).
In C, it is quite simple : It expects rvalues second and third
operands, and yields an rvalue.
In C++ (with simplified rules), if both operands are of the same type
and are lvalues, the result is an lvalue.
If one operand can be implicitly converted to a reference to the other
type, the result is an lvalue.
If one operand has void data type, both operands are converted to void,
and get array-to-pointer, function-to-pointer and lvalue-to-rvalues
conversions, and the result is an rvalue (of void type).
Otherwise the result is an rvalue, and additional obfuscated rules
apply.
If you want to know all the C++ rules for conditional expressions, look
at:
http://www.open-std.org/jtc1/sc22/wg...html#expr.cond
Conversion expressions :
Expect an rvalue operand in C, and yields an rvalue in C.
In C++, they expect and yield an lvalue if the destination type is a
reference type.
From the C++ standard : an lvalue-to-rvalue conversion is: "
4.1 Lvalue-to-rvalue conversion
[conv.lval]

1 An lvalue (_basic.lval_) of a non-function, non-array type T can
be
converted to an rvalue. If T is an incomplete type, a program
that
necessitates this conversion is ill-formed. If the object to
which
the lvalue refers is not an object of type T and is not an object of
a
type derived from T, or if the object is uninitialized, a program
that
necessitates this conversion has undefined behavior. If T is a
non-
class type, the type of the rvalue is the cv-unqualified version of
T.
Otherwise, the type of the rvalue is T. 1)

2 The value contained in the object indicated by the lvalue is
the
rvalue result. When an lvalue-to-rvalue conversion occurs within
the
operand of sizeof (_expr.sizeof_) the value contained in the
refer-
enced object is not accessed, since that operator does not
evaluate
its operand."
I would also like to explain where array-to-pointer conversion occurs.
Knowing that a variable whose type is an array is an lvalue (like any
other variable).

Whenever an lvalue array expression appears as an operand of an
operator that expects an rvalue for that operand, the array-to-pointer
conversion is applied to that operand.
Variadic arguments (i.e. arguments after an ellipsis) get
array-to-pointer conversions (and integer promotion for integer types).
In a conversion expression, if the result is an rvalue (i.e. the
destination type is not a reference type), then the left operand
expects an rvalue, and array-to-pointer conversion occur if the
parameter is of array type.
If the result of a conditional operator (?:) is an rvalue, then the
second and third operand are expected to be rvalues (and
array-to-pointer conversion occur).

One thing that confuse many programmers is the fact that an array can't
be assigned, can't be copy-constructed (in C++), can't be passed as
function parameter, and can't be returned from a function.
What is very confusing for programmers is that you can declare function
parameters which look like arrays but are pointers (good old pointer
automatic variables).
Old K&R C had similar limitations for structures.

If you read the C++ standard, you'll see that there are several places,
where it is explicitly stated that array-to-pointer,
function-to-pointer and lvalue-to-rvalue conversion does not occur!
It is stated in the standard in order to avoid incorrect
interpretations by programmers/compiler-vendors who tend to think that
there are such conversions where there are none.
There is *NO* array-to-pointer (nor lvalue-to-rvalue nor
function-to-pointer) conversion :
1) For the argument of typeid (in C++).
2) When a type is explicitly converted to void
3) On the operand of sizeof
From the C++ standard:

" 4.2 Array-to-pointer conversion
[conv.array]

1 An lvalue or rvalue of type "array of N T" or "array of unknown
bound
of T" can be converted to an rvalue of type "pointer to T."
The
result is a pointer to the first element of the array."

Now I hope that everybody will understand the basics of lvalues and
rvalues.

Jun 6 '06 #20
"SuperKoko" <ta*******@yahoo.fr> writes:
Zach wrote:
Chris Smith wrote:
>
> Sure. An l-value is an expression that may legally appear on the left-
> hand side of the assignment operator, =. An r-value is an expression
> that may appear on the right-hand side. The set of r-values is a subset
> of the the set of l-values. For example, given:
>
> int a;
> int b[50];
>
> The following are l-values (and also r-values):
>
> a
> b[10]
>
> Whereas the following are ONLY r-values:
>
> 17
> a + 5
> b
>
> Therefore, the following line of code will fail to compile:
>
> a + 5 = 15;
>
> Hope that helps,
Where are the rules of what may go on each side?

Since there is a lot of confusion in that discussion, I'll give rules
(based on C++).

How are rules based on C++ helpful in comp.lang.c?
First, I'll correct statements of Chris Smith:
int a;
int b[50];
a is an lvalue
b[10] is an lvalue
17 is an rvalue
a+5 is an rvalue
b *is an lvalue*
b is the name of an array object. As an expression of array type,
if it's not the operand of a unary "&" or "sizeof" operator, it is
implicitly converted to a pointer. C99 6.3.2.1p3:

Except when it is the operand of the sizeof operator or the unary
& operator, or is a string literal used to initialize an array, an
expression that has type "array of _type_" is converted to an
expression with type "pointer to _type_" that points to the
initial element of the array object and is not an lvalue.

Before this conversion takes place, b is an lvalue; after the
conversion, it isn't. Since there isn't really a "before" and
"after", I suppose you could think of it as a kind of Schroedinger's
lvalue. 8-)}

[...]
lvalues are not rvalues and rvalues are not lvalues... They are totally
different concepts.
The C standard doesn't use the term "rvalue" except in a single
footnote, which says:

What is sometimes called "rvalue" is in this International
Standard described as the "value of an expression".

[...] If an lvalue-expression is found in a context where an rvalue is
expected, an rvalue-to-lvalue conversion occurs (and this conversion is
not conceptual... Physical things occur... And HERE can happen
segmentation faults).
I think you mean an lvalue-to-rvalue conversion. I suppose this
refers to fetching the value of the designated object.

[...]
Comma operator: It doesn't expect any particular type of value (i.e. it
accepts both lvalues and rvalues with different semantics). [...] In C, AFAIK, the left operand can be either an rvalue or an lvalue and
the value is discarded (as in C++), but the right operand is expected
to be an rvalue, and the expression yields an rvalue.
In C, the operands are expressions. The left operand is evaluated and
its result is discarded. The right operand is then evaluated and its
result becomes the result of the operation. No need to talk about
"rvalues".

[...]
If you want to know all the C++ rules for conditional expressions, look
at:
http://www.open-std.org/jtc1/sc22/wg...html#expr.cond

And if you want to discuss those rules, I recommend comp.lang.c++.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 7 '06 #21
Keith Thompson wrote:
"SuperKoko" <ta*******@yahoo.fr> writes:
int b[50];
b *is an lvalue*

b is the name of an array object. As an expression of array type,
if it's not the operand of a unary "&" or "sizeof" operator, it is
implicitly converted to a pointer. C99 6.3.2.1p3:

Except when it is the operand of the sizeof operator or the unary
& operator, or is a string literal used to initialize an array, an
expression that has type "array of _type_" is converted to an
expression with type "pointer to _type_" that points to the
initial element of the array object and is not an lvalue.

Before this conversion takes place, b is an lvalue; after the
conversion, it isn't. Since there isn't really a "before" and
"after", I suppose you could think of it as a kind of Schroedinger's
lvalue. 8-)}

I think that the conversion should not take place until b is being
"promoted" as an operand of another operator. (I don't think
the standard text supports this, but I think it should :)

With every other expression in C, you can determine its type
before seeing what context the expression is in. It would be a
"hack" to say that the expression

b

has a different type depending on which larger expression it
appears in. It seems cleaner to say that the above expression
has type (array[50] of int), but when it needs to be converted
to an rvalue (ie. for the purposes of being an operand of an
operator other than & etc.), it gets converted to a pointer.

I think the situation is analogous to:

3U + 3

we could say "3 has type int, except when being added to
an unsigned integer, in which case it has type unsigned int".
(and similar exceptions for the other operators and so forth).
But it is easier to state a rule in terms of promotion.

The case of:

b;

ie. where it is not an operand of anything, could be defined
either way; I don't see what difference it would make.

Jun 7 '06 #22

muttaa wrote:
Chris Smith wrote:
John Bode <jo*******@my-deja.com> wrote:
The following expressions may *not* be lvalues:

array names
functions
enumeration constants
assignment expressions
casts
function calls
Array names? Isn't that the same mistake I made a bit earlier?

Mr.Chris, will you please explain how array names can be an l-value?

Like that:

char array[24];
char (*parray)[24]=&array; /* here, array is an lvalue, and its address
is taken*/
size_t i=sizeof(array); /* here, array is an lvalue and the size of the
array is equal to sizeof(char[24]) */
Otherwise, other expressions having array type get are automatically
converted to a pointer to their first element.

Keith Thompson quoted the standard: C99 6.3.2.1p3:
Except when it is the operand of the sizeof operator or the unary
& operator, or is a string literal used to initialize an array, an
expression that has type "array of _type_" is converted to an
expression with type "pointer to _type_" that points to the
initial element of the array object and is not an lvalue.

C++ has rules which reduce the number of (lvalue or
rvalue)array-to-(rvalue)pointer conversions.
But actually, it doesn't create any real incompatibility.

Jun 7 '06 #23
SuperKoko wrote:
muttaa wrote:
Chris Smith wrote:
John Bode <jo*******@my-deja.com> wrote:
The following expressions may *not* be lvalues:

array names
functions
enumeration constants
assignment expressions
casts
function calls
Array names? Isn't that the same mistake I made a bit earlier? Mr.Chris, will you please explain how array names can be an l-value?

Like that:

char array[24];

Here, array designates a region of storage. Some (not I) call this a
'non-modifiable lvalue'. I submit that array cannot be an lvalue because
it cannot be assigned to.
char (*parray)[24]=&array; /* here, array is an lvalue, and its address
is taken*/
No. parray is the lvalue here. array appears as an rvalue.
size_t i=sizeof(array); /* here, array is an lvalue and the size of the
array is equal to sizeof(char[24]) */
No. array is not an lvalue in any of this.
Otherwise, other expressions having array type get are automatically
converted to a pointer to their first element.

Keith Thompson quoted the standard:
C99 6.3.2.1p3:
Except when it is the operand of the sizeof operator or the unary
& operator, or is a string literal used to initialize an array, an
expression that has type "array of _type_" is converted to an
expression with type "pointer to _type_" that points to the
initial element of the array object and is not an lvalue.

C++ has rules which reduce the number of (lvalue or
rvalue)array-to-(rvalue)pointer conversions.
But actually, it doesn't create any real incompatibility.

I won't deal with your C++ stuff. I do C here.

An lvalue is an expression referring to modifiable storage that neatly
fits on the left side of a simple assignment expression. The expression
array is not one of them.

Of course *(array+0) is an lvalue, as is array[0].

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Jun 7 '06 #24
Joe Wright <jo********@comcast.net> writes:
[...]
An lvalue is an expression referring to modifiable storage that neatly
fits on the left side of a simple assignment expression. The
expression array is not one of them.

Did you consider checking the standard before posting this? Or
perhaps the rest of this thread?

The C standard, unfortunately, has a flawed definition of "lvalue",
but the intent is clear: an lvalue is an expression that designates,
or potentially designates, an object. The definition does not depend
on whether the object is modifiable. If it did, then C99 6.5.3.2
wouldn't make much sense:

The operand of the unary & operator shall be either a function
designator, the result of a [] or unary * operator, or an lvalue
that designates an object that is not a bit-field and is not
declared with the register storage-class specifier.

If "arr" is the name of a declared array object, then &arr is a legal
expression, precisely because arr is an lvalue.

If you want to discuss expressions that can legally appear as the left
operand of an assignment operator, you'll need to find another word or
phrase to use to refer to them (perhaps something like "modifiable
lvalues").

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 7 '06 #25
Joe Wright wrote:

SuperKoko wrote:
char array[24];
Here, array designates a region of storage. Some (not I) call this a
'non-modifiable lvalue'.

Those who do,
are those who are not comfortable
making up their own definitions for technical terms in C.
I submit that array cannot be an lvalue because
it cannot be assigned to. An lvalue is an expression referring to modifiable storage that neatly
fits on the left side of a simple assignment expression.

You, obviously,
*are* comfortable making up your own definitions
for what are technical terms in C.

--
pete
Jun 7 '06 #26
Keith Thompson <ks***@mib.org> wrote:
If you want to discuss expressions that can legally appear as the left
operand of an assignment operator, you'll need to find another word or
phrase to use to refer to them (perhaps something like "modifiable
lvalues").

This seems a bit unreasonable to me. The word l-value predates the C
language specification, and is used across numerous languages to mean
something specific: an expression that may occur on the left-hand side
of an assignment operator.

If the C language specification defines the term otherwise (as it
apparently does), then the logical response would be to interpret the
specification as if the word has the different meaning, but to also
acknowledge the existing uses as valid. This is a pretty universal part
of the human experience; just yesterday, I read a paper that began with
something to the effect of "in this paper, we will consider a sparse
graph to be one with O(n^(3/2)) edges", and yet I can continue to
discuss sparse graphs in the conventional O(n) sense when I'm not
reading that particular paper. I'd suggest the same thing is possible
with the C language specification.

--
Chris Smith - Lead Software Developer / Technical Trainer
MindIQ Corporation
Jun 8 '06 #27
Chris Smith <cd*****@twu.net> writes:
Keith Thompson <ks***@mib.org> wrote:
If you want to discuss expressions that can legally appear as the left
operand of an assignment operator, you'll need to find another word or
phrase to use to refer to them (perhaps something like "modifiable
lvalues").
This seems a bit unreasonable to me. The word l-value predates the C
language specification, and is used across numerous languages to mean
something specific: an expression that may occur on the left-hand side
of an assignment operator.

Ok. I don't think I've seen the term "lvalue" used other than for C
and C++, but of course my experience is not universal.
If the C language specification defines the term otherwise (as it
apparently does), then the logical response would be to interpret the
specification as if the word has the different meaning, but to also
acknowledge the existing uses as valid. This is a pretty universal part
of the human experience; just yesterday, I read a paper that began with
something to the effect of "in this paper, we will consider a sparse
graph to be one with O(n^(3/2)) edges", and yet I can continue to
discuss sparse graphs in the conventional O(n) sense when I'm not
reading that particular paper. I'd suggest the same thing is possible
with the C language specification.

What's *not* reasonable is insisting that the term means some
particular thing while not acknowledging that the C standard defines

I'd say that discussing C in this newsgroup is equivalent to "reading
that particular paper". It's difficult to discuss C if we don't agree
on the definitions of terms used by the C standard, even if common
usage might be different. Otherwise we might as well not have a
standard.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 8 '06 #28

Keith Thompson wrote:
Ok. I don't think I've seen the term "lvalue" used other than for C
and C++, but of course my experience is not universal.

It was also used for B and BCPL:
http://cm.bell-labs.com/cm/cs/who/dmr/kbman.html
http://cm.bell-labs.com/cm/cs/who/dmr/bcpl.pdf
However there was no problem such as non-modifiable lvalue, because all
lvalues could effectively appear on the left side of an assignment
operator.

It worth noticing that BCPL had a 'rv' and a 'lv' keyword (whose C
equivalent is & and *).
If you think about how to program a BCPL compiler, you'll see that
these two notions are very simple, and would appear in a compiler's
code.
Any expression yields a word (the only data type) ... And there are two
types of expressions:
Expressions yielding a word, and the value of the word is the value it
designates (and thus, for instance, adding 0 to this value doesn't
change this value). These expressions are named rvalues.
Expressions yielding a word designating a place in memory (i.e. a
reference) ... And to get the real value of the object, the compiler
has to dereference this word (and thus, adding 0 to this value yields a
rvalue which is the value designated-to by the lvalue). Such
expressions are called lvalue.

The rv operator interprets a lvalue word as if it were an rvalue.
The lv operator interprets an rvalue word as if it were an lvalue, and
if it is applied to an lvalue it first convert the lvalue to an rvalue
by accessing the memory designated by the lvalue (anyway, this
conversion occurs anywhere, when a lvalue is found in a place where an
rvalue is expected).

This C reference manual (1975):
http://cm.bell-labs.com/cm/cs/who/dmr/cman.pdf

Says that identifiers are lvalues... But also says that array
identifiers are not lvalues but rvalues equal to the pointer to their
first element. It even says "Because of this conversion, arrays are not
lvalues".
On another hand, it says that address-of operator can only be applied
on lvalue (hence it can't be applied on array identifiers).
It also says that the unary * operator yields an lvalue (but it doesn't
say that it yields an rvalue if the operand is of type
pointer-to-array).

Note that structs were not assignable and were lvalues... That's why
IMHO saying that an lvalue can always be put on the left side of an
assignment operator is not a good definition.

Jun 8 '06 #29
Keith Thompson <ks***@mib.org> wrote:
I'd say that discussing C in this newsgroup is equivalent to "reading
that particular paper". It's difficult to discuss C if we don't agree
on the definitions of terms used by the C standard, even if common
usage might be different. Otherwise we might as well not have a
standard.

Okay. Perhaps I just misinterpreted your statement: "If you want to
discuss expressions that can legally appear as the left operand of an
assignment operator, you'll need to find another word or phrase to use
to refer to them". If you specifically meant in this newsgroup, then we
don't disagree.

--
Chris Smith - Lead Software Developer / Technical Trainer
MindIQ Corporation
Jun 8 '06 #30
Chris Smith <cd*****@twu.net> writes:
Keith Thompson <ks***@mib.org> wrote:
I'd say that discussing C in this newsgroup is equivalent to "reading
that particular paper". It's difficult to discuss C if we don't agree
on the definitions of terms used by the C standard, even if common
usage might be different. Otherwise we might as well not have a
standard.

Okay. Perhaps I just misinterpreted your statement: "If you want to
discuss expressions that can legally appear as the left operand of an
assignment operator, you'll need to find another word or phrase to use
to refer to them". If you specifically meant in this newsgroup, then we
don't disagree.

Yes, I specifically meant in this newsgroup.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Jun 8 '06 #31
pete wrote:
If (b) was not an lvalue,
then (&b) would be undefined.

But that's not true.

For example, if (b) is a function, which is not an lvalue, or the
result of a [] or unary * operator, either an lvalue or not, (&b) is
still well-defined.

Jun 17 '06 #32
whyglinux wrote:

pete wrote:
If (b) was not an lvalue,
then (&b) would be undefined.
But that's not true.

For example, if (b) is a function, which is not an lvalue,

I meant if (b) was an rvalue instead of an lvalue.
or the result of a []
Any result of a [], is an lvalue.
or unary * operator, either an lvalue or not,
(&b) is still well-defined.

--
pete
Jun 17 '06 #33
pete wrote:
Any result of a [], is an lvalue.

If you were right, then

6.5.3.2 Address and indirection operators, paragraph 1:
"The operand of the unary & operator shall be either a function
designator, the result of a [] or unary * operator, or an lvalue that
designates an object that is not a bit-field and isnot declared with
the register storage-class specifier."

would had been written like this:

The operand of the unary & operator shall be either a function
designator or an lvalue that designates an object that is not a
bit-field and is not declared with the register storage-class
specifier.

But this is not true. Therefore, although "the result of a [] or unary
* operator" is usually an lvalue, but must not be only an lvalue here.
The difference between "the result of a [] or unary * operator" and an
lvalue is that "the result" can be either an lvalue or rvalue.

Not only a function or a qualified lvalue, but also an rvalue, only if
it is "the result of a [] or unary * operator", can be taken as the
operand of the unary & operator. Rvalue operand is a case that needs
to be listed specially.

Jun 17 '06 #34
whyglinux wrote:

pete wrote:
Any result of a [], is an lvalue.
If you were right, then

6.5.3.2 Address and indirection operators, paragraph 1:
"The operand of the unary & operator shall be either a function
designator, the result of a [] or unary * operator, or an lvalue that
designates an object that is not a bit-field and isnot declared with
the register storage-class specifier."

would had been written like this:

The operand of the unary & operator shall be either a function
designator or an lvalue that designates an object that is not a
bit-field and is not declared with the register storage-class
specifier.

There's no evidence that that is true.
But this is not true. Therefore, although "the result of a [] or unary
* operator" is usually an lvalue, but must not be only an lvalue here.

The result of a [] has an address.
[] is a binary operator,
with a[b] being equal to *((a) + (b)).
The address of a[b] is ((a) + (b)).
Everything that has an address in a C program,
is either a function or an object.
Function pointers aren't allowed as operands
of the addition operator, so the pointer part of a[b],
must be an object pointer, and a[b] must be an object.

If you were right, then you could give an example
where the result of the [] operator, is not an lvalue.

--
pete
Jun 17 '06 #35
pete wrote:
whyglinux wrote:

pete wrote:
Any result of a [], is an lvalue.

If you were right, then

6.5.3.2 Address and indirection operators, paragraph 1:
"The operand of the unary & operator shall be either a function
designator, the result of a [] or unary * operator, or an lvalue that
designates an object that is not a bit-field and isnot declared with
the register storage-class specifier."

would had been written like this:

The operand of the unary & operator shall be either a function
designator or an lvalue that designates an object that is not a
bit-field and is not declared with the register storage-class
specifier.

There's no evidence that that is true.
But this is not true. Therefore, although "the result of a [] or unary
* operator" is usually an lvalue, but must not be only an lvalue here.

The result of a [] has an address.
[] is a binary operator,
with a[b] being equal to *((a) + (b)).
The address of a[b] is ((a) + (b)).
Everything that has an address in a C program,
is either a function or an object.
Function pointers aren't allowed as operands
of the addition operator, so the pointer part of a[b],
must be an object pointer, and a[b] must be an object.

If you were right, then you could give an example
where the result of the [] operator, is not an lvalue.

It's easy. The following is an example:

typedef struct A {
int x[10];
} A;

A func() {
A a;
return a;
}

int main( void )
{
int* p0 = &(func().x[0]);
/*This is valid though func().x[0] is an rvalue object */
/* Note: for C99 only.
C89 does not permit to take an rvalue's address in any case. */

/* &(func().x) is invalid because func().x is an rvalue array, and is
neither the result of a [] operator nor that of a * operator. */

return 0;
}

In fact, not all objects are lvalues (for example, the returned objects
by functions). The Standard should point this out but fails to do so,
perhaps due to the fact that taking an rvalue object's address is rare
and seems useless in C.

Jun 17 '06 #36
whyglinux wrote:

pete wrote:
If you were right, then you could give an example
where the result of the [] operator, is not an lvalue.

It's easy. The following is an example:

typedef struct A {
int x[10];
} A;

A func() {
A a;
return a;
}

int main( void )
{
int* p0 = &(func().x[0]);
/*This is valid though func().x[0] is an rvalue object */
/* Note: for C99 only.
C89 does not permit to take an rvalue's address in any case. */

I tend to have a C89 bias,
which I now admit means that I may be wrong on this topic.
In fact, not all objects are lvalues
(for example, the returned objects by functions).
The Standard should point this out but fails to do so,
perhaps due to the fact that taking an rvalue object's address is rare
and seems useless in C.

--
pete
Jun 17 '06 #37
whyglinux <wh*******@gmail.com> wrote:
typedef struct A {
int x[10];
} A;

A func() {
A a;
return a;
}

int main( void )
{
int* p0 = &(func().x[0]);
/*This is valid though func().x[0] is an rvalue object */
/* Note: for C99 only.
C89 does not permit to take an rvalue's address in any case. */

/* &(func().x) is invalid because func().x is an rvalue array, and is
neither the result of a [] operator nor that of a * operator. */

return 0;
}

In fact, not all objects are lvalues (for example, the returned objects
by functions). The Standard should point this out but fails to do so,
perhaps due to the fact that taking an rvalue object's address is rare
and seems useless in C.

Indeed, this is a peculiar situation, and one I think at best poorly
covered in both C89 and C99. Even if you can do the above with "p0",
you can never *use* p0 in any way after that.

It probably would have been better (in my opinion at least) if both
standards said something like this:

When a function returns a structure value, this produces a
value-context object. The only defined operations on a
value-context object are:

- to discard it entirely, or
- to copy it wholly, as by assignment to an ordinary
object or parameter, or
- to take a pointer to it whose value is not used beyond the
next sequence point, or
- to select an element (via the "." operator), producing a
value-context object to which these rules apply recursively.

For example, if f() has a structure return value with elements
x and y, and x has array type and y has type int:

struct S { int x[N]; int y; /* and possibly others */ };
struct S f(void);
struct S r;
void g(int);

(void) f(); /* valid (discarded entirely) */
r = f(); /* valid (copied wholly) */
g(f().y); /* valid (element selected then copied wholly) */

memcpy(r.x, f().x, sizeof r.x); /* invalid -- f().x is
not being "copied wholly"; instead, a pointer is taken
and used beyond the next sequence point */
memcpy(&r.x[0], &f().x[0], sizeof r.x); /* still invalid,
for the same reason */

r.x[0] = f().x[0]; /* valid (albeit complicated!) */

Note that these rules also permit one to write, e.g.:

g((&(f()))->y);

I have fully parenthesized this to show where the operators bind:
f() returns a "struct S"; we take the address of this "value context
object" -- or "rvalue object" if you prefer such terms -- but
immediately, without an intervening sequence point, use the "->"
operator to select an element whose value is then copied wholly,
to be sent as a parameter value to g().

The above rules probably need some additional clarification (probably
grouped with the unary "*" operator) so that it is clear that "*",
applied to one of these funny pointers resulting from taking the
address of a "value-context object", produces the actual value-
context object in question, to which the special rules apply.

All of this leaves room for a future C standard to define operations
on entire arrays, so that one can write:

r.x = f().x;

to copy the whole "x" array without copying the "y" value. And, in
any case, the goal is to make the lifetime of a "value-context
object" that of a single between-sequence-points region, as if
there were a brace-enclosed local variable involved, whose lifetime
is only that of the expression:

int h(int *);

h(f().x); /* invalid */

is treated much as if we had written something like:

int h(int *);
int *p;
{
struct S temp;
temp = f();
p = &temp.x[0];
/* note that uses of both p and *p are valid here ... */
}
/* but uses of p or *p are undefined here */
h(p);

This mirrors how compilers are often likely to treat structure-valued
functions: they "return" an object whose lifetime is that of a stack
temporary, created just long enough to run the expression(s) involved,
and the way the value is "returned" is via a secret parameter. That
is:

g(f().y);

is compiled as something very much like:

{ struct S temp; f(&temp); g(temp.y); }

in a number of actual implementations. I only say "very much like"
because the temp.x space may be re-used or discarded even "inside
the braces" here, e.g., assembly code like:

sub #44,sp /* make stack space for "temp" */
lea 0(sp),r1
call f /* f(&temp) */
add #40,sp /* delete temp.x but leave temp.y */
mov (sp)+,r1 /* fetch temp.y and finish deleting temp */
call g /* g(that) */

(on a machine with a stack, and arguments passed in registers r1
onward).
--
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
Reading email is like searching for food in the garbage, thanks to spammers.
Jun 17 '06 #38
On 2006-06-17, Chris Torek <no****@torek.net> wrote:
whyglinux <wh*******@gmail.com> wrote:
typedef struct A {
int x[10];
} A;

A func() {
A a;
return a;
}

int main( void )
{
int* p0 = &(func().x[0]);
/*This is valid though func().x[0] is an rvalue object */
/* Note: for C99 only.
C89 does not permit to take an rvalue's address in any case. */

/* &(func().x) is invalid because func().x is an rvalue array, and is
neither the result of a [] operator nor that of a * operator. */

return 0;
}

In fact, not all objects are lvalues (for example, the returned objects
by functions). The Standard should point this out but fails to do so,
perhaps due to the fact that taking an rvalue object's address is rare
and seems useless in C.

Indeed, this is a peculiar situation, and one I think at best poorly
covered in both C89 and C99. Even if you can do the above with "p0",
you can never *use* p0 in any way after that.
[...]

I just think life would have been simpler if you couldn't return
structure instances at all-- after all you can't return arrays. I don't
know if this ability to return struct instances was in the earliest
versions of C or if it was added later.

Practically speaking it's quite a convenient feature and not often a
cause of real-world problems I suppose. But functions always return
values, and objects are (everywhere else) not values, but places you can
store values. Allowing objects to be returned from functions introduces
an inconsistency.
Jun 17 '06 #39
Ben C wrote:

I just think life would have been simpler if you couldn't return
structure instances at all-- after all you can't return arrays. I don't
know if this ability to return struct instances was in the earliest
versions of C or if it was added later.
Arrays don't have copy or assignment semantics, structures do. To
return something by value, you have to copy it. So it does make sense
to be able to return a structure and not an array.
Practically speaking it's quite a convenient feature and not often a
cause of real-world problems I suppose. But functions always return
values, and objects are (everywhere else) not values, but places you can
store values. Allowing objects to be returned from functions introduces
an inconsistency.

But you can assign to one, so it is consistent to be able to return one.

--
Ian Collins.
Jun 17 '06 #40
On 2006-06-17, Ian Collins <ia******@hotmail.com> wrote:
Ben C wrote:

I just think life would have been simpler if you couldn't return
structure instances at all-- after all you can't return arrays. I don't
know if this ability to return struct instances was in the earliest
versions of C or if it was added later.

Arrays don't have copy or assignment semantics, structures do. To
return something by value, you have to copy it. So it does make sense
to be able to return a structure and not an array.

Yes, exactly, the two things go hand-in-hand.

I had a look on Google and found that this has been discussed here
before. Structure assignment, and the possibility of passing and
returning struct instances was a "recent extension" in 1978. In K&R C

http://tinyurl.com/p635q
Practically speaking it's quite a convenient feature and not often a
cause of real-world problems I suppose. But functions always return
values, and objects are (everywhere else) not values, but places you can
store values. Allowing objects to be returned from functions introduces
an inconsistency.

But you can assign to one, so it is consistent to be able to return one.

That part's consistent, but structure returning _does_ give rise to an
inconsistency: a struct instance returned from a function is by
(standard) definition an rvalue, even though it's an object. Some
compilers let you assign to it anyway. And it is I think the only way to
contrive an rvalue that's "the result of the [] operator", in the
example we just saw from the previous poster.
Jun 18 '06 #41

### This discussion thread is closed

Replies have been disabled for this discussion.