Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

non-lvalue arrays

230 views
Skip to first unread message

Andrea Griffini

unread,
Nov 2, 2002, 4:05:24 PM11/2/02
to
Hello...

In our italian newsgroup dedicated to the C language
it has been asked if the following code is legal:

typedef struct ST { int x[10]; } S;

S foo() { S s; s.x[2]=3; return s; }

void bar()
{
printf("%i\n",foo().x[2]);
}

Now, the documents say that a member of a structure
returned from a function is not an lvalue; does this
imply the existence of non-lvalue arrays ? If this
is the case how can x[y] be evaluated if that is
equivalent to *(x+y) and such an array has no address ?

gcc 2.95 gives an error if asked to compile

*(foo().x+2)

but compiles fine

foo().x[2]


TIA for any clarification on this point ...

Andrea

lawrenc...@eds.com

unread,
Nov 3, 2002, 3:19:23 PM11/3/02
to
Andrea Griffini <agr...@tin.it> wrote:
>
> Now, the documents say that a member of a structure
> returned from a function is not an lvalue; does this
> imply the existence of non-lvalue arrays ? If this
> is the case how can x[y] be evaluated if that is
> equivalent to *(x+y) and such an array has no address ?

Yes, there are non-lvalue arrays. They weren't useful prior to C99
because the array to pointer conversion only happened to lvalue arrays;
C99 performs the conversion even for non-lvalue arrays, so your code is
valid C99 (but not valid C90). Non-lvalue arrays do have addresses, but
the address is only valid until the next sequence point. See 6.3.2.1p3
and 6.5.2.2p5.

-Larry Jones

Oh yeah? You just wait! -- Calvin

Jun Woong

unread,
Nov 4, 2002, 11:23:58 AM11/4/02
to
<lawrenc...@eds.com> wrote in message
news:luu3qa...@cvg-65-27-189-87.cinci.rr.com...

> Andrea Griffini <agr...@tin.it> wrote:
> >
> > Now, the documents say that a member of a structure
> > returned from a function is not an lvalue; does this
> > imply the existence of non-lvalue arrays ? If this
> > is the case how can x[y] be evaluated if that is
> > equivalent to *(x+y) and such an array has no address ?
>
> Yes, there are non-lvalue arrays. They weren't useful prior to C99
> because the array to pointer conversion only happened to lvalue arrays;
> C99 performs the conversion even for non-lvalue arrays, so your code is
> valid C99 (but not valid C90).

Interesting.

What about the following in C90?

foo().x; /* invalid or not? (I surmise it's invalid) */

If the above is valid, what's the result of the following?

sizeof(foo().x);


Thanks in advance.


--
Jun, Woong (myco...@hanmail.net)
Dept. of Physics, Univ. of Seoul

Zaza

unread,
Nov 4, 2002, 3:05:03 PM11/4/02
to

> Yes, there are non-lvalue arrays. They weren't useful prior to C99
> because the array to pointer conversion only happened to lvalue arrays;
> C99 performs the conversion even for non-lvalue arrays, so your code is
> valid C99 (but not valid C90). Non-lvalue arrays do have addresses, but
> the address is only valid until the next sequence point. See 6.3.2.1p3

hello,

does c99 said anything about allocation in a temporary memory for structure
returned by function or non-lvalue array?

Thanks.


lawrenc...@eds.com

unread,
Nov 4, 2002, 6:19:24 PM11/4/02
to
Jun Woong <myco...@hanmail.net> wrote:
>
> What about the following in C90?
>
> foo().x; /* invalid or not? (I surmise it's invalid) */

I believe it's valid. Although it has an array type rather than the
pointer type most C programmers would expect, it's in a void expression
context so the array value (whatever it is) is discarded. I don't see
any provisions in the Standard that are being violated.

> If the above is valid, what's the result of the following?
>
> sizeof(foo().x);

The declared size of the array member. sizeof doesn't require an
lvalue, and the lvalue to pointer conversion never occurs in a sizeof
context.

-Larry Jones

I like Mom to be impressed when I fulfill the least of my obligations.
-- Calvin

lawrenc...@eds.com

unread,
Nov 4, 2002, 6:19:24 PM11/4/02
to
Zaza <francesco....@libero.it> wrote:
>
> does c99 said anything about allocation in a temporary memory for structure
> returned by function or non-lvalue array?

Not explicitly, it just says that attempting to modify such a value or
attempting to access it after the next sequence point produces undefined
behavior.

-Larry Jones

I keep forgetting that rules are only for little nice people. -- Calvin

Jun Woong

unread,
Nov 4, 2002, 10:36:06 PM11/4/02
to
<lawrenc...@eds.com> wrote in message
news:tat6qa...@cvg-65-27-189-87.cinci.rr.com...

> Jun Woong <myco...@hanmail.net> wrote:
> >
> > What about the following in C90?
> >
> > foo().x; /* invalid or not? (I surmise it's invalid) */
>
> I believe it's valid. Although it has an array type rather than the
> pointer type most C programmers would expect, it's in a void expression
> context so the array value (whatever it is) is discarded. I don't see
> any provisions in the Standard that are being violated.
>

C90 (structure and union member operators):
] The value is that of the named member ...

But, there is no provision which gives its interpretation; there is
nothing to say about the non-lvalue array (i.e., the array value) in
C90, which seems to mean it's undefined behavior to me.

C90 (definition of undefined behavior):
] Undefined behavior is otherwise indicated in this International
] Standard by the words "undefined behavior" or by the omission of any
] explicit definition of behavior.

C90 (definition of array type):
] An array type describes a contiguously allocated non-empty set of
] *objects* with a particular member object type. called "the element
] rype." [the emphasis is mine]

All array types has to be an object by definition.

> > If the above is valid, what's the result of the following?
> >
> > sizeof(foo().x);
>
> The declared size of the array member. sizeof doesn't require an
> lvalue, and the lvalue to pointer conversion never occurs in a sizeof
> context.

I believe the same interpretation as above goes for the this case.

C90 allows the sizeof operator to be applied to an array whose
declaration uses the storage class specifier "register".

register int x[10];
sizeof(x); /* 10 * sizeof(int) */

But the "register" object is an lvalue whose address cannot be
obtained. Even if the sizeof operator doesn't evaluate the operand,
the type of the operand "foo().x" is not an array (by definition). So
what is its type? I have no idea, but the Standard also seems not to
give the exact answer for this.

Most compilers agree with you; they doesn't fail to translate both
codes above. But, at the present time I think the result of both is
undefined behavior.

Please enlighten me on this old and curious problem.

Jun Woong

unread,
Nov 5, 2002, 12:45:38 AM11/5/02
to
<lawrenc...@eds.com> wrote in message
news:tat6qa...@cvg-65-27-189-87.cinci.rr.com...

> Jun Woong <myco...@hanmail.net> wrote:
> >
> > What about the following in C90?
> >
> > foo().x; /* invalid or not? (I surmise it's invalid) */
>
> I believe it's valid. Although it has an array type rather than the
> pointer type most C programmers would expect, it's in a void expression
> context so the array value (whatever it is) is discarded. I don't see
> any provisions in the Standard that are being violated.
>
> > If the above is valid, what's the result of the following?
> >
> > sizeof(foo().x);
>
> The declared size of the array member. sizeof doesn't require an
> lvalue, and the lvalue to pointer conversion never occurs in a sizeof
> context.
>

I canceled my clumsy posting, so if you happen to see it, please
ignore.

Let me follow the reasoning of interpreting the expression in question.

The result of the function call is a value, not an lvalue. So the
result of the call to the function "foo()" is a value of type
"struct ST."

foo() /* a value of type struct ST */

The structure member operator . requires its left operand to be of
stucture type. So it's allowed to apply the operator to the above
result in both C90 and C99.

foo(). [...];

The right operand of the . operator has to be a member designator, and
"x" is a member of "struct ST", which is allowed.

foo().x;

This expression has the same type as that of the deisgnated member -
"array of int", and it's not an lvalue since the left operand is not
an lvalue; so it's, say, "an array value".

Now, a question: AFAICK, a value doesn't exist on the storage in C,
thus it doesn't meet the definition of "object". If I am right, how
can the above expression has the type "array"? By definition, an array
describes a set of objects.

] An array type describes a contiguously allocated nonempty set of
] *objects* with a particular member object type, called the element
] type.

C99 doesn't change in this regard since C90. So I think it results in
undefined behavior in both C90 and C99. Am I missing something here?

If the expression can't have the type "array", the sizeof operation
applied to it would also be undefined behavior, I believe.

lawrenc...@eds.com

unread,
Nov 6, 2002, 12:19:23 PM11/6/02
to
Jun Woong <myco...@hanmail.net> wrote:
>
> foo().x;
>
> This expression has the same type as that of the deisgnated member -
> "array of int", and it's not an lvalue since the left operand is not
> an lvalue; so it's, say, "an array value".
>
> Now, a question: AFAICK, a value doesn't exist on the storage in C,
> thus it doesn't meet the definition of "object". If I am right, how
> can the above expression has the type "array"? By definition, an array
> describes a set of objects.

I'm having a hard time understanding that first sentence, but I think
the answer is that the storage *does* have a value. It's an array
value, which doesn't occur in any other context, but it's analogous to a
struct value. There are objects there even though there's no lvalue,
strange as that may appear. If there were an lvalue, it would open the
door to more horrible consequences.

-Larry Jones

I thought my life would seem more interesting with a musical
score and a laugh track. -- Calvin

t...@cs.ucr.edu

unread,
Nov 7, 2002, 10:59:04 AM11/7/02
to
lawrenc...@eds.com wrote:
+ Zaza <francesco....@libero.it> wrote:
+>
+> does c99 said anything about allocation in a temporary memory for structure
+> returned by function or non-lvalue array?
+
+ Not explicitly, it just says that attempting to modify such a value or
+ attempting to access it after the next sequence point produces undefined
+ behavior.

Are you sure that

i = ++f().count; /* where f returns a struct by value */

yields undefined behavior under C99? (IIUC, under C++, the behavior
would be defined.)

Tom Payne

James Kuyper Jr.

unread,
Nov 7, 2002, 8:17:02 PM11/7/02
to
...

> + Not explicitly, it just says that attempting to modify such a value or
> + attempting to access it after the next sequence point produces
undefined
> + behavior.
>
> Are you sure that
>
> i = ++f().count; /* where f returns a struct by value */
>
> yields undefined behavior under C99? (IIUC, under C++, the behavior
> would be defined.)

Yes, I'm sure, because Lawrence Jones wasn't just making it up, he was
making an almost word-for-word citation of section 6.5.2.2p5 from the
C99 standard:

"If an attempt is made to modify the result of a function call or to
access it after the next sequence point, the behavior is undefined."

Zaza

unread,
Nov 8, 2002, 10:13:22 AM11/8/02
to

<t...@cs.ucr.edu> ha scritto nel messaggio news:aqe2k8$72a$1...@glue.ucr.edu...

> lawrenc...@eds.com wrote:
> + Zaza <francesco....@libero.it> wrote:
> +>
> +> does c99 said anything about allocation in a temporary memory for
structure
> +> returned by function or non-lvalue array?
> +
> + Not explicitly, it just says that attempting to modify such a value or
> + attempting to access it after the next sequence point produces undefined
> + behavior.
>
> Are you sure that
>
> i = ++f().count; /* where f returns a struct by value */
>
> yields undefined behavior under C99?

This code have also an error: the ++ operatore must have a l-value
exspression while f().cout is a r-value.
If the left operand of . operator is an r-value (like f()) then the right
operand isn't a l-value.

> (IIUC, under C++, the behavior
> would be defined.)

It's Right, but in C++ there are the temporary object.

> Tom Payne

Best regards.

Jun Woong

unread,
Nov 8, 2002, 11:12:50 AM11/8/02
to
<lawrenc...@eds.com> wrote in message
news:npgbqa...@cvg-65-27-189-87.cinci.rr.com...

> Jun Woong <myco...@hanmail.net> wrote:
> >
> > foo().x;
> >
> > This expression has the same type as that of the deisgnated member -
> > "array of int", and it's not an lvalue since the left operand is not
> > an lvalue; so it's, say, "an array value".
> >
> > Now, a question: AFAICK, a value doesn't exist on the storage in C,
> > thus it doesn't meet the definition of "object". If I am right, how
> > can the above expression has the type "array"? By definition, an array
> > describes a set of objects.
>
> I'm having a hard time understanding that first sentence, but I think
> the answer is that the storage *does* have a value.

This seems to imply the existence of the temporary object as in C++.
AFAICK C doesn't have such a concept for the return value of a
function. Why didn't the concept be introduced when putting the
structure and union type into the nearly first-class citizen?

> It's an array
> value, which doesn't occur in any other context, but it's analogous to a
> struct value. There are objects there even though there's no lvalue,
> strange as that may appear. If there were an lvalue, it would open the
> door to more horrible consequences.
>

If the official interpretation can be derived from the current
definition of "array," or it is revised to include the concept of
"array value", I'd fully agree with your interpretation.

I'm sorry for not trying to find more elaborated interpretation
due to lack of time. :(

t...@cs.ucr.edu

unread,
Nov 8, 2002, 10:59:51 AM11/8/02
to
Zaza <francesco....@libero.it> wrote:
+
+ <t...@cs.ucr.edu> ha scritto nel messaggio news:aqe2k8$72a$1...@glue.ucr.edu...
+> lawrenc...@eds.com wrote:

+> + Zaza <francesco....@libero.it> wrote:
+> +>
+> +> does c99 said anything about allocation in a temporary memory for
+ structure
+> +> returned by function or non-lvalue array?

+> +
+> + Not explicitly, it just says that attempting to modify such a value or
+> + attempting to access it after the next sequence point produces undefined
+> + behavior.
+>
+> Are you sure that
+>
+> i = ++f().count; /* where f returns a struct by value */
+>
+> yields undefined behavior under C99?
+
+ This code have also an error: the ++ operatore must have a l-value
+ exspression while f().cout is a r-value.
+ If the left operand of . operator is an r-value (like f()) then the right
+ operand isn't a l-value.

Thanks.

I presume that the same would be true of f().count[2] if count were an
array member of the returned value. Right?

Tom Payne

Ross Ridge

unread,
Nov 8, 2002, 12:08:27 PM11/8/02
to
<t...@cs.ucr.edu> wrote:
> Are you sure that

>
> i = ++f().count; /* where f returns a struct by value */
>
> yields undefined behavior under C99?

Zaza <francesco....@libero.it> wrote:
> This code have also an error: the ++ operatore must have a l-value
> exspression while f().cout is a r-value.
> If the left operand of . operator is an r-value (like f()) then the right
> operand isn't a l-value.

<t...@cs.ucr.edu> wrote:
>I presume that the same would be true of f().count[2] if count were an
>array member of the returned value. Right?

The [] operator in C doesn't require l-values for either of it's operands.

Ross Ridge

--
l/ // Ross Ridge -- The Great HTMU
[oo][oo] rri...@csclub.uwaterloo.ca
-()-/()/ http://www.csclub.uwaterloo.ca/u/rridge/
db //

Al Grant

unread,
Nov 8, 2002, 1:47:16 PM11/8/02
to
"James Kuyper Jr." <kuy...@wizard.net> wrote in message news:<3DCB108E...@wizard.net>...

> "If an attempt is made to modify the result of a function call or to
> access it after the next sequence point, the behavior is undefined."

Presumably the array can be passed as a variadic argument without
violating either of these conditions?

Andrea Griffini

unread,
Nov 8, 2002, 1:53:29 PM11/8/02
to
On Fri, 08 Nov 2002 15:13:22 GMT, "Zaza"
<francesco....@libero.it> wrote:

>> Are you sure that
>>
>> i = ++f().count; /* where f returns a struct by value */
>>
>> yields undefined behavior under C99?
>
>This code have also an error: the ++ operatore must have a l-value
>exspression while f().cout is a r-value.

It is perfectly valid if count is of a user defined class
that implements an operator++ (no matter if const or not).
In C++ you can even write the apparently surprising

X() = X();

where you're calling the assignment operator on a temporary
object. "l" and "r" in lvalue and rvalue lost much of their
meaning for user defined classes.

Andrea

James Kuyper

unread,
Nov 8, 2002, 2:00:53 PM11/8/02
to

I'm not entirely clear what you're suggesting. Could you provide example
code?

You can't pass arrays as arguments to functions. You can pass a pointer
to the array, or you can pass a structure containing the array, but not
the array itself. If you pass a pointer to the array into a function,
then if that function uses that pointer to modify the array, it's in
violation of 6.5.2.2p5. If you pass the structure to a function, what
that function actually recieves is a copy of the original structure; and
it's perfectly free to modify the copy; that doesn't qualify as
modifying the original.

Zaza

unread,
Nov 8, 2002, 3:44:14 PM11/8/02
to

"Andrea Griffini" <agr...@tin.it> ha scritto nel messaggio
news:3dcc067...@news.tin.it...

> On Fri, 08 Nov 2002 15:13:22 GMT, "Zaza"
> <francesco....@libero.it> wrote:
>
> >> Are you sure that
> >>
> >> i = ++f().count; /* where f returns a struct by value */
> >>
> >> yields undefined behavior under C99?
> >
> >This code have also an error: the ++ operatore must have a l-value
> >exspression while f().cout is a r-value.
>
> It is perfectly valid if count is of a user defined class
> that implements an operator++ (no matter if const or >not).

yes, but this situations is possible only in C++. In C99 it doesn't respect
the semantic of ++ operator.

Fra.

Philip Lantz

unread,
Nov 8, 2002, 4:04:36 PM11/8/02
to
James Kuyper wrote:
>
> Al Grant wrote:
> >
> > "James Kuyper Jr." <kuy...@wizard.net> wrote in message news:<3DCB108E...@wizard.net>...
> > > "If an attempt is made to modify the result of a function call or to
> > > access it after the next sequence point, the behavior is undefined."
> >
> > Presumably the array can be passed as a variadic argument without
> > violating either of these conditions?
>
> I'm not entirely clear what you're suggesting. Could you provide example
> code?
>
> You can't pass arrays as arguments to functions. You can pass a pointer
> to the array, or you can pass a structure containing the array, but not
> the array itself. If you pass a pointer to the array into a function,
> then if that function uses that pointer to modify the array, it's in
> violation of 6.5.2.2p5.

In fact, the function can't even use the pointer to access the array,
due
to the sequence point after evaluation of the arguments.

Al Grant

unread,
Nov 11, 2002, 1:16:32 PM11/11/02
to
James Kuyper <kuy...@saicmodis.com> wrote in message news:<3DCC09E5...@saicmodis.com>...

> Al Grant wrote:
> > "James Kuyper Jr." <kuy...@wizard.net> wrote in message news:<3DCB108E...@wizard.net>...
> > > "If an attempt is made to modify the result of a function call or to
> > > access it after the next sequence point, the behavior is undefined."
> >
> > Presumably the array can be passed as a variadic argument without
> > violating either of these conditions?
>
> I'm not entirely clear what you're suggesting. Could you provide example
> code?

In C90:

struct S { char a[6]; };
struct S g(void);
void f(int, ...);
void h() { f(0, g().a); }

Where does C90 say that this either converts to pointer or is illegal?

Jun Woong

unread,
Nov 11, 2002, 1:43:09 PM11/11/02
to
"Al Grant" <alg...@myrealbox.com> wrote in message
news:5765b025.02111...@posting.google.com...

C90 6.2.2.1:
] An lvalue is an expression (with an object type or an incomplete
] type other than void) that designates an object.

and the return value of a function is not an lvalue, which means that
the return value of the function designates no object.

The definition of the array type says:
] An /array/ type describes a contiguously allocated nonempty set of
] objects ...

Now, the question is:
can the value which designates no object have the type which describe
the set of objects?

If the answer to this question is yes, I think your interpretation is
correct even if it seems very strange. But if the answer is no, then
the type of g().a is undefined. And C99 also has the same problem in
fact.

Thanks.

James Kuyper

unread,
Nov 11, 2002, 2:16:24 PM11/11/02
to
Al Grant wrote:
>
> James Kuyper <kuy...@saicmodis.com> wrote in message news:<3DCC09E5...@saicmodis.com>...
> > Al Grant wrote:
> > > "James Kuyper Jr." <kuy...@wizard.net> wrote in message news:<3DCB108E...@wizard.net>...
> > > > "If an attempt is made to modify the result of a function call or to
> > > > access it after the next sequence point, the behavior is undefined."
> > >
> > > Presumably the array can be passed as a variadic argument without
> > > violating either of these conditions?
> >
> > I'm not entirely clear what you're suggesting. Could you provide example
> > code?
>
> In C90:
>
> struct S { char a[6]; };
> struct S g(void);
> void f(int, ...);
> void h() { f(0, g().a); }
>
> Where does C90 say that this either converts to pointer or is illegal?

I can't speak to C90, I don't have a copy of the old standard. I've no
particular interest in the C90 standard, with the C99 standard being
fully three years old by now. Searching backwards through this thread, I
find that it broke into two parts. The one intiated by Jun Woong is
asking about C90, but the one initiated by Zaza has always been about
C99; every comment I've made on this thread was in Zaza's part. In
particular, the citation I made which you quoted above was explicitly
labelled as a citation from C99.

With reference to the C99 standard, the answer to your question is:

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

t...@cs.ucr.edu

unread,
Nov 11, 2002, 2:19:59 PM11/11/02
to
Jun Woong <myco...@hanmail.net> wrote:
[...]
+> In C90:
+>
+> struct S { char a[6]; };
+> struct S g(void);
+> void f(int, ...);
+> void h() { f(0, g().a); }
+>
+> Where does C90 say that this either converts to pointer or is illegal?
+
+ C90 6.2.2.1:
+ ] An lvalue is an expression (with an object type or an incomplete
+ ] type other than void) that designates an object.
+
+ and the return value of a function is not an lvalue, which means that
+ the return value of the function designates no object.

It's my understanding that the C99 committee dropped this definition
of "lvalue" because it did not include such syntactically correct
expressions as "*(int*)0" --- in fact, it left a situation where the
lvalueness of an expression could not be determined at compile time.
(Unfortunately, the C99 remedy makes "1+2" an lvalue.)

+ The definition of the array type says:
+ ] An /array/ type describes a contiguously allocated nonempty set of
+ ] objects ...
+
+ Now, the question is:
+ can the value which designates no object have the type which describe
+ the set of objects?
+
+ If the answer to this question is yes, I think your interpretation is
+ correct even if it seems very strange. But if the answer is no, then
+ the type of g().a is undefined. And C99 also has the same problem in
+ fact.

The distinction between rvalue and lvalue breaks down when structs are
returned by value. The C++ committee recognized this and has tried to
side-step the issues with the notion of temporary objects. That
attempt isn't elegant, but as far as I can tell it works.

Tom Payne

t...@cs.ucr.edu

unread,
Nov 11, 2002, 2:36:11 PM11/11/02
to
James Kuyper <kuy...@saicmodis.com> wrote:

+ Al Grant wrote:
[...]
+> In C90:
+>
+> struct S { char a[6]; };
+> struct S g(void);
+> void f(int, ...);
+> void h() { f(0, g().a); }
+>
+> Where does C90 say that this either converts to pointer or is illegal?
+
+ I can't speak to C90, I don't have a copy of the old standard. I've no
+ particular interest in the C90 standard, with the C99 standard being
+ fully three years old by now. Searching backwards through this thread, I
+ find that it broke into two parts. The one intiated by Jun Woong is
+ asking about C90, but the one initiated by Zaza has always been about
+ C99; every comment I've made on this thread was in Zaza's part. In
+ particular, the citation I made which you quoted above was explicitly
+ labelled as a citation from C99.
+
+ With reference to the C99 standard, the answer to your question is:
+
+ 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.'

It follows that "g().a" is a pointer rvalue (that designates a pointer
value) which points to the initial element of an array object that is
the sole member of the non-object of type S returned by g(). Yuck!

Tom Payne

Jun Woong

unread,
Nov 11, 2002, 3:27:33 PM11/11/02
to
<t...@cs.ucr.edu> wrote in message news:aqovsv$blp$1...@glue.ucr.edu...

> Jun Woong <myco...@hanmail.net> wrote:
> [...]
> +> In C90:
> +>
> +> struct S { char a[6]; };
> +> struct S g(void);
> +> void f(int, ...);
> +> void h() { f(0, g().a); }
> +>
> +> Where does C90 say that this either converts to pointer or is illegal?
> +
> + C90 6.2.2.1:
> + ] An lvalue is an expression (with an object type or an incomplete
> + ] type other than void) that designates an object.
> +
> + and the return value of a function is not an lvalue, which means that
> + the return value of the function designates no object.
>
> It's my understanding that the C99 committee dropped this definition
> of "lvalue" because it did not include such syntactically correct
> expressions as "*(int*)0" --- in fact, it left a situation where the
> lvalueness of an expression could not be determined at compile time.
> (Unfortunately, the C99 remedy makes "1+2" an lvalue.)
>

In C99 g().a is decayed to a pointer, but the same thing doesn't go
for C90; there is no woding to say about the conversion of the array
type to the pointer in that case. Thus, if the type of g().a can be
of type "array", then it remains as an array even when it occur within
the function call expression.

> + The definition of the array type says:
> + ] An /array/ type describes a contiguously allocated nonempty set of
> + ] objects ...
> +
> + Now, the question is:
> + can the value which designates no object have the type which describe
> + the set of objects?
> +
> + If the answer to this question is yes, I think your interpretation is
> + correct even if it seems very strange. But if the answer is no, then
> + the type of g().a is undefined. And C99 also has the same problem in
> + fact.
>
> The distinction between rvalue and lvalue breaks down when structs are
> returned by value.

This is what I'd like to claim as I said in other branch of this
thread.

lawrenc...@eds.com

unread,
Nov 11, 2002, 4:19:27 PM11/11/02
to
Jun Woong <myco...@hanmail.net> wrote:
>
> This seems to imply the existence of the temporary object as in C++.
> AFAICK C doesn't have such a concept for the return value of a
> function. Why didn't the concept be introduced when putting the
> structure and union type into the nearly first-class citizen?

You'd have to ask DMR -- he's the one who made structs and unions into
nearly first-class citizens (in 1978 or thereabouts).

> If the official interpretation can be derived from the current
> definition of "array," or it is revised to include the concept of
> "array value", I'd fully agree with your interpretation.

I misspoke when I said that array values don't occur in any other
context, they do. In particular, when you take sizeof an array, an
array value (albeit unevaluated) is what you're taking the size of.

-Larry Jones

That gives me a FABULOUS idea. -- Calvin

Jun Woong

unread,
Nov 11, 2002, 5:28:11 PM11/11/02
to
<lawrenc...@eds.com> wrote in message
news:o94pqa...@cvg-65-27-189-87.cinci.rr.com...

The sizeof operator decides its size from the *type*, not the value.

sizeof(foo().a);

In order for this expression to be well-defined, you have to be able
to say the type of foo().a. Now, the same question again:

Can the value which designates no object have the type which describe
the set of objects?

If the answer to this question is yes, all problems in C99 which I
can think of in this regard are resolved. But the answer makes a
horrible monster in C90 as we can see in Al Grant's example.

But please note that it's not my real intention to object your
previous interpretation.

Thanks.

t...@cs.ucr.edu

unread,
Nov 11, 2002, 5:18:29 PM11/11/02
to
Jun Woong <myco...@hanmail.net> wrote:
+ <t...@cs.ucr.edu> wrote in message news:aqovsv$blp$1...@glue.ucr.edu...
+> Jun Woong <myco...@hanmail.net> wrote:
+> [...]
+> +> In C90:

+> +>
+> +> struct S { char a[6]; };
+> +> struct S g(void);
+> +> void f(int, ...);
+> +> void h() { f(0, g().a); }

+> +>
+> +> Where does C90 say that this either converts to pointer or is illegal?
+> +
+> + C90 6.2.2.1:
+> + ] An lvalue is an expression (with an object type or an incomplete
+> + ] type other than void) that designates an object.

+> +
+> + and the return value of a function is not an lvalue, which means that
+> + the return value of the function designates no object.
+>
+> It's my understanding that the C99 committee dropped this definition
+> of "lvalue" because it did not include such syntactically correct
+> expressions as "*(int*)0" --- in fact, it left a situation where the
+> lvalueness of an expression could not be determined at compile time.
+> (Unfortunately, the C99 remedy makes "1+2" an lvalue.)
+>
+
+ In C99 g().a is decayed to a pointer, but the same thing doesn't go
+ for C90; there is no woding to say about the conversion of the array
+ type to the pointer in that case. Thus, if the type of g().a can be
+ of type "array", then it remains as an array even when it occur within
+ the function call expression.

Hmmmmm. C90 6.2.2.1, paragraph 3:

Except when it is the operand of the sizeof operatior, the unary &
operator, or is a character string literal used to initialize an array
of character type, or is a wide string literal used to initialize an
array with element type compatible with wchar_t, an lvalue that has
type "array of type" is converted to an expression that has type
"pointer to type" that points to the initial element of the arrray


object and is not an lvalue.

But you knew that already, so your point must be that "g().a" is not
an lvalue. That view seems to be supported by C90 6.3.2.3:

A postfix expression followed by a dot . and an identifier
designates a member of a structure or union object. The value is that
of the named member, and is an lvalue if the first expression is an
lvalue.

But if g().a isn't an array lvalue and isn't a pointer-to-char rvalue,
what is it? An array rvalue?

Tom Payne

Jun Woong

unread,
Nov 11, 2002, 5:59:13 PM11/11/02
to
<t...@cs.ucr.edu> wrote in message news:aqpabl$cpb$1...@glue.ucr.edu...

> Jun Woong <myco...@hanmail.net> wrote:
[...]
> +
> + In C99 g().a is decayed to a pointer, but the same thing doesn't go
> + for C90; there is no woding to say about the conversion of the array
> + type to the pointer in that case. Thus, if the type of g().a can be
> + of type "array", then it remains as an array even when it occur within
> + the function call expression.
>
> Hmmmmm. C90 6.2.2.1, paragraph 3:
>
> Except when it is the operand of the sizeof operatior, the unary &
> operator, or is a character string literal used to initialize an array
> of character type, or is a wide string literal used to initialize an
> array with element type compatible with wchar_t, an lvalue that has
> type "array of type" is converted to an expression that has type
> "pointer to type" that points to the initial element of the arrray
> object and is not an lvalue.
>
> But you knew that already, so your point must be that "g().a" is not
> an lvalue. That view seems to be supported by C90 6.3.2.3:
>
> A postfix expression followed by a dot . and an identifier
> designates a member of a structure or union object. The value is that
> of the named member, and is an lvalue if the first expression is an
> lvalue.
>
> But if g().a isn't an array lvalue and isn't a pointer-to-char rvalue,
> what is it? An array rvalue?
>

I have no idea. That's what I'm asking now. With the same definition
of the type "array", in order to make C99's intention work well we
have to agree that there is an "array value". But this also make an
"array value" monster which is never decayed to a pointer in C90. I
guess that the Committee wouldn't care for this since C90 has already
been superseded.

lawrenc...@eds.com

unread,
Nov 12, 2002, 11:19:27 AM11/12/02
to
Jun Woong <myco...@hanmail.net> wrote:
>
> The sizeof operator decides its size from the *type*, not the value.

True, but what is it the type *of*? The (unevaluated) array value.

> Can the value which designates no object have the type which describe
> the set of objects?

Yes, just as a value that is not an object can nonetheless have an
object type.

-Larry Jones

These findings suggest a logical course of action. -- Calvin

lawrenc...@eds.com

unread,
Nov 12, 2002, 12:19:26 PM11/12/02
to
Al Grant <alg...@myrealbox.com> wrote:
>
> In C90:
>
> struct S { char a[6]; };
> struct S g(void);
> void f(int, ...);
> void h() { f(0, g().a); }
>
> Where does C90 say that this either converts to pointer or is illegal?

I don't think it does. It should be clear that it doesn't convert to a
pointer, but I don't see anything making it invalid, either. I consider
that a defect in C90.

-Larry Jones

My upbringing is filled with inconsistent messages. -- Calvin

lawrenc...@eds.com

unread,
Nov 12, 2002, 12:19:26 PM11/12/02
to
t...@cs.ucr.edu wrote:
>
> But if g().a isn't an array lvalue and isn't a pointer-to-char rvalue,
> what is it? An array rvalue?

Exactly.

-Larry Jones

Hello, local Navy recruitment office? Yes, this is an emergency... -- Calvin

t...@cs.ucr.edu

unread,
Nov 12, 2002, 1:59:24 PM11/12/02
to
lawrenc...@eds.com wrote:
+ t...@cs.ucr.edu wrote:
+>
+> But if g().a isn't an array lvalue and isn't a pointer-to-char rvalue,
+> what is it? An array rvalue?
+
+ Exactly.

And, since subscripting is an operation on pointer rvalues, then
the expression "g().a[0]" is ill formed. Right?

Tom Payne

Jun Woong

unread,
Nov 12, 2002, 7:24:55 PM11/12/02
to
<lawrenc...@eds.com> wrote:
> Jun Woong <myco...@hanmail.net> wrote:
> >
> > The sizeof operator decides its size from the *type*, not the value.
>
> True, but what is it the type *of*? The (unevaluated) array value.
>
> > Can the value which designates no object have the type which describe
> > the set of objects?
>
> Yes, just as a value that is not an object can nonetheless have an
> object type.
>

Okay, I missed that point.
I can accept your argument without doubt.

Jun Woong

unread,
Nov 12, 2002, 7:36:24 PM11/12/02
to

Yes. In g().a[0] the indirection operator is applying to an array
value, not a pointer value, which requires a diagnostic. This can be
true only with C90.

0 new messages