# — conversion of array to pointer not limited to lvalues

Discussion in 'C Programming' started by nicolas.sitbon@gmail.com, Aug 4, 2008.

1. ### Guest

hi everybody, In the new feature of C99, i find "— conversion of array
to pointer not limited to lvalues" : what does it mean? I don't find
any difference between C90 and C99 about conversion of array to
pointer.
Thanks.

, Aug 4, 2008

2. ### Chris TorekGuest

Re: conversion of array to pointer not limited to lvalues

In article <>
<> wrote:
>hi everybody, In the new feature of C99, i find "conversion of array
>to pointer not limited to lvalues" : what does it mean?

It means:

#define N 100 /* or some other constant */

struct A {
char arr[N];
};

struct A f(void);

void example(void) {
char c;

c = f().arr[10];
}

is now valid (it was not valid in C89). The function f() returns
an "rvalue" (or more simply, a "value"), not an "lvalue" (something
that designates, or at least potentially designates, an object).

In most C code, the only time you encounter an array, it is an
array object -- an lvalue -- as in:

char buf[30];
...
buf[10] = 'x';

Here "buf" names the entire array, but the array is an object --
a region of data storage; in this case it is the array named "buf"
-- and the <object, array N of T, buf> triple is converted to a
<value, pointer to T, &buf[0]> triple. That is, the "lvalue" that
names the entire array is converted to an "rvalue" (i.e., an ordinary
value) that points to the first element of the array.

In C89, only lvalue-arrays were converted to rvalue-pointers.
Since rvalue-arrays are relatively rare -- they arise only from
function calls like the one above, and some other rarely-encountered
expressions -- one tends not to see this in real C code.

(The other reason one tends not to find this in "real" or "working"
C code is that compilers given source code like this will, at least
relatively often, produce object code that does not work correctly.
Even in C99, it is somewhat hard to use this conversion safely.
Consider, for instance:

char *p;

p = f().arr;
printf("[0] = %c\n", p[0]);
printf("[4] = %c\n", p[4]);
}

Depending on how the call is implemented, p[0] and p[4] may well
no longer exist by the time the printf() calls are made. The first
printf() may print the desired value, but the call to printf() may
change the byte accessed by the second call, so that the second
printf() prints something other than what the programmer expected.)
--
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: gmail (figure it out) http://web.torek.net/torek/index.html

Chris Torek, Aug 4, 2008

3. ### Guest

Re: conversion of array to pointer not limited to lvalues

I'm sory but I don't understand the difference between a lvalue-arrays
and a rvalue-arrays?
Are you saying that
struct A
{
char arr[N];
};

and
char arr2[N];
are conceptually different?

, Aug 4, 2008
4. ### Barry SchwarzGuest

On Mon, 4 Aug 2008 10:44:05 -0700 (PDT),
wrote:

>hi everybody, In the new feature of C99, i find "— conversion of array
>to pointer not limited to lvalues" : what does it mean? I don't find
>any difference between C90 and C99 about conversion of array to
>pointer.

You didn't look carefully enough, though I don't know what the real
impact of the wording change is.

In C89, para 3.2.2.1 says "Except when ..., an lvalue that has
type ``array of type '' is converted ..."

In C99, para 6.3.2.1-3 say "Except when ..., an expression that has
type ‘‘array of type’’ is converted ..."

In the new wording, the expression need not be an lvalue. Maybe
someone who worked on the standard can explain how this affects the
average programmer or if it is something only a compiler writer would

--
Remove del for email

Barry Schwarz, Aug 4, 2008
5. ### Harald van DÄ³kGuest

Re: conversion of array to pointer not limited to lvalues

On Mon, 04 Aug 2008 12:39:45 -0700, nicolas.sitbon wrote:
> I'm sory but I don't understand the difference between a lvalue-arrays
> and a rvalue-arrays?
> Are you saying that
> struct A
> {
> char arr[N];
> };
>
> and
> char arr2[N];
> are conceptually different?

Not directly, as far as the array is concerned. However, the former is an
allowable function return type, while the latter is not.

Harald van DÄ³k, Aug 4, 2008
6. ### santoshGuest

Re: conversion of array to pointer not limited to lvalues

wrote:

> I'm sory but I don't understand the difference between a lvalue-arrays
> and a rvalue-arrays?
> Are you saying that
> struct A
> {
> char arr[N];
> };
>
> and
> char arr2[N];
> are conceptually different?

Aren't they? They are different types. The first one is type struct A
and the second one is type char [N].

But the point is wrapping an array within a structure allows one to
return an array from functions, which cannot return plain arrays.
However the manner in which it is accessed is different from how you
would normally access an array, and this has been standardised by C99.
Since functions return values, you must store the entire structure (or
at least it's array member) in another object or you will lose it.

Please see Chris Torek's post. You can't get a better explanation than
that.

santosh, Aug 4, 2008
7. ### Guest

Re: conversion of array to pointer not limited to lvalues

On 4 aoÃ»t, 21:56, Harald van DÄ³k <> wrote:
> On Mon, 04 Aug 2008 12:39:45 -0700, nicolas.sitbon wrote:
> > I'm sory but I don't understand the difference between a lvalue-arrays
> > and a rvalue-arrays?
> > Are you saying that
> > struct A
> > {
> > Â  Â char arr[N];
> > };

>
> > and
> > char arr2[N];
> > are conceptually different?

>
> Not directly, as far as the array is concerned. However, the former is an
> allowable function return type, while the latter is not.

the structure is returned, not the table directly.

, Aug 4, 2008
8. ### santoshGuest

Re: conversion of array to pointer not limited to lvalues

wrote:

> On 4 août, 21:56, Harald van D?k <> wrote:
>> On Mon, 04 Aug 2008 12:39:45 -0700, nicolas.sitbon wrote:
>> > I'm sory but I don't understand the difference between a
>> > lvalue-arrays and a rvalue-arrays?
>> > Are you saying that
>> > struct A
>> > {
>> > char arr[N];
>> > };

>>
>> > and
>> > char arr2[N];
>> > are conceptually different?

>>
>> Not directly, as far as the array is concerned. However, the former
>> is an allowable function return type, while the latter is not.

>
> the structure is returned, not the table directly.

A value of type struct A is returned which contains an array member of
type char [n]. You can do this too:

struct A ret = foo(); /* returns a struct A value */
printf("%c\n", ret.arr[0]);

printf("%c\n", foo().arr[0]);

santosh, Aug 4, 2008
9. ### Guest

Re: conversion of array to pointer not limited to lvalues

On 4 août, 22:06, santosh <> wrote:
> wrote:
> > On 4 août, 21:56, Harald van D?k <> wrote:
> >> On Mon, 04 Aug 2008 12:39:45 -0700, nicolas.sitbon wrote:
> >> > I'm sory but I don't understand the difference between a
> >> > lvalue-arrays and a rvalue-arrays?
> >> > Are you saying that
> >> > struct A
> >> > {
> >> > char arr[N];
> >> > };

>
> >> > and
> >> > char arr2[N];
> >> > are conceptually different?

>
> >> Not directly, as far as the array is concerned. However, the former
> >> is an allowable function return type, while the latter is not.

>
> > the structure is returned, not the table directly.

>
> A value of type struct A is returned which contains an array member of
> type char [n]. You can do this too:
>
>  struct A ret = foo(); /* returns a struct A value */
>  printf("%c\n", ret.arr[0]);
>
>
>  printf("%c\n", foo().arr[0]);

OK, I know that, but except the fact that we can return the table
(which is in a structure), what's the difference between the two table?

, Aug 4, 2008
10. ### Barry SchwarzGuest

Re: conversion of array to pointer not limited to lvalues

On Mon, 4 Aug 2008 12:39:45 -0700 (PDT),
wrote:

>I'm sory but I don't understand the difference between a lvalue-arrays
>and a rvalue-arrays?
>Are you saying that
>struct A
>{
> char arr[N];
>};
>
>and
>char arr2[N];
>are conceptually different?

I don't understand many facets of lvalue and rvalue either but one
obvious difference is that your struct is only a declaration of a type
while your arr2 is the definition of an object. If you define a
struct A named x, there is still one obvious difference. Passing x to
a function will result in a complete copy of the array arr being
passed to the function. Passing arr2 to a similar function will
result in the address of the array being passed. In the first case,
updates to array elements are local to the called function. In the
function.

--
Remove del for email

Barry Schwarz, Aug 4, 2008
11. ### Guest

Re: conversion of array to pointer not limited to lvalues

On 4 août, 23:01, Barry Schwarz <> wrote:
> On Mon, 4 Aug 2008 12:39:45 -0700 (PDT),
> wrote:
>
> >I'm sory but I don't understand the difference between a lvalue-arrays
> >and a rvalue-arrays?
> >Are you saying that
> >struct A
> >{
> >   char arr[N];
> >};

>
> >and
> >char arr2[N];
> >are conceptually different?

>
> I don't understand many facets of  lvalue and rvalue either but one
> obvious difference is that your struct is only a declaration of a type
> while your arr2 is the definition of an object.  If you define a
> struct A named x, there is still one obvious difference.  Passing x to
> a function will result in a complete copy of the array arr being
> passed to the function.  Passing arr2 to a similar function will
> result in the address of the array being passed.  In the first case,
> updates to array elements are local to the called function.  In the
> second, updates are made directly to the array in the calling
> function.
>
> --
> Remove del for email

I know all of this details but I have some difficulties with this
notion of lvalues/rvalues. In all case a table is nothing more than a
data storage so what's the difference that affects the "l/r
valuability" (oh my god, my poor English)?.

, Aug 4, 2008
12. ### Guest

Re: conversion of array to pointer not limited to lvalues

wrote:
> On 4 aoï¿½t, 22:06, santosh <> wrote:
> > wrote:
> > > On 4 aoï¿½t, 21:56, Harald van D?k <> wrote:
> > >> On Mon, 04 Aug 2008 12:39:45 -0700, nicolas.sitbon wrote:
> > >> > I'm sory but I don't understand the difference between a
> > >> > lvalue-arrays and a rvalue-arrays?
> > >> > Are you saying that
> > >> > struct A
> > >> > {
> > >> > char arr[N];
> > >> > };

> >
> > >> > and
> > >> > char arr2[N];
> > >> > are conceptually different?

> >
> > >> Not directly, as far as the array is concerned. However, the former
> > >> is an allowable function return type, while the latter is not.

> >
> > > the structure is returned, not the table directly.

> >
> > A value of type struct A is returned which contains an array member of
> > type char [n]. You can do this too:
> >
> > ï¿½struct A ret = foo(); /* returns a struct A value */
> > ï¿½printf("%c\n", ret.arr[0]);
> >
> >
> > ï¿½printf("%c\n", foo().arr[0]);

>
> OK, I know that, but except the fact that we can return the table
> (which is in a structure), what's the difference between the two table?

None. Everything relevant to your question depends only upon that one
difference. As a result of that difference, any situation in which C
requires an lvalue is a situation that an array member of a struct
value returned by a function call doesn't satisfy. The implications of
this include the fact that you can't increment/decrement it with ++ or
--, and you can't assign a value to it. Such an array needn't reside
array - it might sit in one or more registers. Since the subscript
operator is normally defined in terms of address arithmetic, you need
a special case like this to allow the elements of such an array to be
accessed.

, Aug 4, 2008
13. ### Keith ThompsonGuest

Re: conversion of array to pointer not limited to lvalues

writes:
> On 4 août, 23:01, Barry Schwarz <> wrote:
>> On Mon, 4 Aug 2008 12:39:45 -0700 (PDT),
>> wrote:
>>
>> >I'm sory but I don't understand the difference between a lvalue-arrays
>> >and a rvalue-arrays?
>> >Are you saying that
>> >struct A
>> >{
>> >   char arr[N];
>> >};

>>
>> >and
>> >char arr2[N];
>> >are conceptually different?

>>
>> I don't understand many facets of  lvalue and rvalue either but one
>> obvious difference is that your struct is only a declaration of a type
>> while your arr2 is the definition of an object.  If you define a
>> struct A named x, there is still one obvious difference.  Passing x to
>> a function will result in a complete copy of the array arr being
>> passed to the function.  Passing arr2 to a similar function will
>> result in the address of the array being passed.  In the first case,
>> updates to array elements are local to the called function.  In the
>> second, updates are made directly to the array in the calling
>> function.

>
> I know all of this details but I have some difficulties with this
> notion of lvalues/rvalues. In all case a table is nothing more than a
> data storage so what's the difference that affects the "l/r
> valuability" (oh my god, my poor English)?.

An lvalue is an expression that designates an object.

The difference here is that the value returned by a function isn't
(considered to be) an object, even if it's a structure.

If a function returns an array -- well, a function *can't* return an
array, so instead it will typically return a pointer to the first
element of an array. And that pointer has to point to an object
that's been created in some other manner (a declared object, a
malloc()ed object, a string literal, a piece of some larger object,
etc.).

If a function returns a structure, it just returns the *value* of that
structure; conceptually at least, there's no object that holds that
value and whose address you could take. (In practice, there's likely
to be a struct object somewhere in memory, created by the code
generated by the compiler, but that "object" isn't visible as an
object to C code, so it doesn't count.)

If the structure contains an array, then you have an array that's not
an object; the change in C99 allows indexing into that array.

As far as I know, this case (a function returning a structure that
contains an array) is the only case where you can have an array
expression without a corresponding array object.

--
Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson, Aug 5, 2008
14. ### Guest

Re: conversion of array to pointer not limited to lvalues

On 5 août, 01:49, Keith Thompson <> wrote:
> writes:
> > On 4 août, 23:01, Barry Schwarz <> wrote:
> >> On Mon, 4 Aug 2008 12:39:45 -0700 (PDT),
> >> wrote:

>
> >> >I'm sory but I don't understand the difference between a lvalue-arrays
> >> >and a rvalue-arrays?
> >> >Are you saying that
> >> >struct A
> >> >{
> >> >   char arr[N];
> >> >};

>
> >> >and
> >> >char arr2[N];
> >> >are conceptually different?

>
> >> I don't understand many facets of  lvalue and rvalue either but one
> >> obvious difference is that your struct is only a declaration of a type
> >> while your arr2 is the definition of an object.  If you define a
> >> struct A named x, there is still one obvious difference.  Passing x to
> >> a function will result in a complete copy of the array arr being
> >> passed to the function.  Passing arr2 to a similar function will
> >> result in the address of the array being passed.  In the first case,
> >> updates to array elements are local to the called function.  In the
> >> second, updates are made directly to the array in the calling
> >> function.

>
> > I know all of this details but I have some difficulties with this
> > notion of lvalues/rvalues. In all case a table is nothing more than a
> > data storage  so what's the difference that affects the "l/r
> > valuability" (oh my god, my poor English)?.

>
> An lvalue is an expression that designates an object.
>
> The difference here is that the value returned by a function isn't
> (considered to be) an object, even if it's a structure.
>
> If a function returns an array -- well, a function *can't* return an
> array, so instead it will typically return a pointer to the first
> element of an array.  And that pointer has to point to an object
> that's been created in some other manner (a declared object, a
> malloc()ed object, a string literal, a piece of some larger object,
> etc.).
>
> If a function returns a structure, it just returns the *value* of that
> structure; conceptually at least, there's no object that holds that
> value and whose address you could take.  (In practice, there's likely
> to be a struct object somewhere in memory, created by the code
> generated by the compiler, but that "object" isn't visible as an
> object to C code, so it doesn't count.)
>
> If the structure contains an array, then you have an array that's not
> an object; the change in C99 allows indexing into that array.
>
> As far as I know, this case (a function returning a structure that
> contains an array) is the only case where you can have an array
> expression without a corresponding array object.
>
> --
> Keith Thompson (The_Other_Keith)  <http://www.ghoti.net/~kst>
> Nokia
> "We must do something.  This is something.  Therefore, we must do this."
>     -- Antony Jay and Jonathan Lynn, "Yes Minister"

OK, I understand what you say, sorry and thanks for your explanation.
it's now clear for me.
Thanks all.

, Aug 5, 2008
15. ### Huibert BolGuest

Re: conversion of array to pointer not limited to lvalues

Keith Thompson wrote:

> As far as I know, this case (a function returning a structure that
> contains an array) is the only case where you can have an array
> expression without a corresponding array object.

A ternairy operator that results in a structure that contains an array
is a second.

- Huibert.

Huibert Bol, Aug 5, 2008
16. ### Keith ThompsonGuest

Re: conversion of array to pointer not limited to lvalues

Huibert Bol <> writes:
> Keith Thompson wrote:
>> As far as I know, this case (a function returning a structure that
>> contains an array) is the only case where you can have an array
>> expression without a corresponding array object.

>
> A ternairy operator that results in a structure that contains an array
> is a second.

Sounds interesting, but I'm not quite seeing it. I'd think that in
order for the tenary operator to result in such a struct expression,
its second or third operand would have to be such a struct expression,
so that's not really a distinct case, any more than a parenthesized
function call would be.

I was thinking that a C99 compound literal might be another case, but
it's not, because it "provides an unnamed object whose value is given
by the initializer list" (C99 6.5.2.5p4). This is similar to an array
literal.

--
Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson, Aug 6, 2008
17. ### Harald van DÄ³kGuest

Re: conversion of array to pointer not limited to lvalues

On Tue, 05 Aug 2008 18:42:57 -0700, Keith Thompson wrote:
> Huibert Bol <> writes:
>> Keith Thompson wrote:
>>> As far as I know, this case (a function returning a structure that
>>> contains an array) is the only case where you can have an array
>>> expression without a corresponding array object.

>>
>> A ternairy operator that results in a structure that contains an array
>> is a second.

>
> Sounds interesting, but I'm not quite seeing it. I'd think that in
> order for the tenary operator to result in such a struct expression, its
> second or third operand would have to be such a struct expression,

Right.

> so
> that's not really a distinct case, any more than a parenthesized
> function call would be.

If a is declared as
struct A a;
then
(rand() ? a : a)
is not an lvalue, even though a is.

(a = a)
is also not an lvalue, and is a third way of getting a non-lvalue
structure.

Harald van DÄ³k, Aug 6, 2008
18. ### Chris TorekGuest

Re: conversion of array to pointer not limited to lvalues

>On Tue, 05 Aug 2008 18:42:57 -0700, Keith Thompson wrote:
>>... I'd think that in order for the tenary operator to result
>>in such a struct expression, its second or third operand would
>>have to be such a struct expression,

(in fact, they must both be struct expressions, with identical
struct types)

>> so that's not really a distinct case, any more than a parenthesized
>> function call would be.

They convert lvalues to rvalues, though.

In article <4b568\$489948fb\$541dfcd3\$1.nb.home.nl>
Harald van DÄ³k <> wrote:
>If a is declared as
> struct A a;
>then
> (rand() ? a : a)
>is not an lvalue, even though a is.
>
> (a = a)
>is also not an lvalue, and is a third way of getting a non-lvalue
>structure.

In C++, the rules are different. This is only *almost* irrelevant,
and this is why: In all of these cases, there is an underlying
lvalue "out there" (namely, the object named "a" in the above code
fragmnets), and it would have been possible to define the operators
so that the result *is* an lvalue. For instance, one could redefine
the ?: operator such that:

((a ? b : c) = d)

becomes meaningful whenever b and c have identical types, or even
merely types-that-are-compatible-with-d, with the meaning being
that of:

(a ? (b = d) : (c = d))

and in this case, ?: would not remove "lvalue-ness" from its second
and third operands. Similarly, assignment could have been defined
to leave lvalue-ness alone. (They are not, and we have to deal
with the language as it is, not as it might be, of course. But
this does relate to C in at least one way: C compiler bugs one
finds regarding use of func().array_member tend not to affect these
other forms of expression, or at least not as often, because those
bugs often arise from compiler-writers making mistakes in tracking
"lvalue-ness". Such a mistake winds up being "harmless" -- other
than failure to generate a required diagnostic, anyway -- when
there is an "underlying lvalue" that the compiler accidentally
uses. There is one for everything except func().array_member.
[In the func().array_member case, the "lvalue" the compiler manages
to come up with is often a stack temporary that is subsequently
clobbered. The runtime behavior seen when using this can be
difficult to debug.])
--
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: gmail (figure it out) http://web.torek.net/torek/index.html

Chris Torek, Aug 6, 2008
19. ### Keith ThompsonGuest

Re: conversion of array to pointer not limited to lvalues

Chris Torek <> writes:
>>On Tue, 05 Aug 2008 18:42:57 -0700, Keith Thompson wrote:
>>>... I'd think that in order for the tenary operator to result
>>>in such a struct expression, its second or third operand would
>>>have to be such a struct expression,

>
> (in fact, they must both be struct expressions, with identical
> struct types)
>
>>> so that's not really a distinct case, any more than a parenthesized
>>> function call would be.

>
> They convert lvalues to rvalues, though.

Yes, thanks, that's the point I was missing. And thanks to Harald
too.

[snip]

--
Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson, Aug 6, 2008