Rvalue of struct type

S

SRR

Consider the following code:
#include <stdio.h>
#include <string.h>
struct test{
char a[100];
}

funTest( void );
int main( void )
{
printf("%s",funTest().a);
return 0;
}

struct test funTest()
{
struct test foo;
strcpy(foo.a,"Hello");
return foo;
}


In this I want to know how the following expression statement works:
printf("%s",funTest().a);

funTest() is evaluated to yield an rvalue of type, "struct test" and
the expression "funTest().a" yields an rvalue of type array of char,
which is converted to an rvalue equal to the pointer to the first
element of the char array and is passed to the printf() function.

My doubt is, since "funTest().a" yields an rvalue of type, array of
char, how can it be converted to pointer type when we can have pointer
only for Lvalues and not for Rvalues.

Hope my question is clear.

Thanks in advance for the reply.
 
G

Guest

SRR said:
Consider the following code:
#include <stdio.h>
#include <string.h>
struct test{
char a[100];
}

funTest( void );

While valid, this is really bad style. It looks like you forgot a
semicolon and expect funTest to return int, when you really do mean to
make funTest return struct test.
int main( void )
{
printf("%s",funTest().a);
return 0;
}

struct test funTest()
{
struct test foo;
strcpy(foo.a,"Hello");
return foo;
}


In this I want to know how the following expression statement works:
printf("%s",funTest().a);

funTest() is evaluated to yield an rvalue of type, "struct test" and
the expression "funTest().a" yields an rvalue of type array of char,
which is converted to an rvalue equal to the pointer to the first
element of the char array and is passed to the printf() function.
Correct.

My doubt is, since "funTest().a" yields an rvalue of type, array of
char, how can it be converted to pointer type when we can have pointer
only for Lvalues and not for Rvalues.

The pointer points to a temporary, and accessing that temporary after
the next sequence point, or modifying it, results in undefined
behaviour. (If you don't know what a sequence point is, please ask.)

char c = funTest().a[0]; /* valid, initialises c with 'H' */
char *p = funTest().a; /* valid, initialised p with a pointer value */
c = *p; /* invalid, accessing the function call's result after the
next sequence point */

funTest().a[0] = 'H'; /* invalid, modifying function call's result */

char str[100];
strcpy(str, funTest().a); /* invalid, accessing the function call's
result after the next sequence point */
 
S

SRR

SRR said:
Consider the following code:
#include <stdio.h>
#include <string.h>
struct test{
       char a[100];
}
funTest( void );

While valid, this is really bad style. It looks like you forgot a
semicolon and expect funTest to return int, when you really do mean to
make funTest return struct test.
Yes! You are right. But I did it inadvertantly while pasting the code.
Actually I typed it as
struct test{
char a[100];
}funTest( void );
Thanks for your comment abouy it.
The pointer points to a temporary, and accessing that temporary after
the next sequence point, or modifying it, results in undefined
behaviour. (If you don't know what a sequence point is, please ask.)
Thanks, I know the concept of Sequence Point. A function Call is a
sequence point as all the arguments are evaluated including all side
effects before entering the function.
Therefore my code produces undefined behavior as the temporary storage
may no longer contain the required data!
Now I understood why I got run time error when I compiled and executed
the code using Dev-CPP for Windows OS, but it executed well with
TurboCPP for MS-Dos.
Thanks once again for helping me understand what is really happening.
char c = funTest().a[0]; /* valid, initialises c with 'H' */
char *p = funTest().a; /* valid, initialised p with a pointer value */
c = *p; /* invalid, accessing the function call's result after the
next sequence point */

funTest().a[0] = 'H'; /* invalid, modifying function call's result */

char str[100];
strcpy(str, funTest().a); /* invalid, accessing the function call's
result after the next sequence point */- Hide quoted text -
Let us extend the topic. Is this the only case, when an rvalue of type
array is converted to rvalue of type pointer to the first element of
the array using temporary storage?
Any other possibility?
Thanks in advance for the reply.
 
S

SRR

SRR said:
Consider the following code:
#include <stdio.h>
#include <string.h>
struct test{
       char a[100];
}
funTest( void );

While valid, this is really bad style. It looks like you forgot a
semicolon and expect funTest to return int, when you really do mean to
make funTest return struct test.




int main( void )
{
    printf("%s",funTest().a);
    return 0;
}
struct test funTest()
{
       struct test foo;
       strcpy(foo.a,"Hello");
       return foo;
}
In this I want to know how the following expression statement works:
printf("%s",funTest().a);
funTest() is evaluated to yield an rvalue of type, "struct test" and
the expression "funTest().a" yields an rvalue of type array of char,
which is converted to an rvalue equal to the pointer to the first
element of the char array and is passed to the printf() function.
Correct.

My doubt is, since "funTest().a" yields an rvalue of type, array of
char, how can it be converted to pointer type when we can have pointer
only for Lvalues and not for Rvalues.

The pointer points to a temporary, and accessing that temporary after
the next sequence point, or modifying it, results in undefined
behaviour. (If you don't know what a sequence point is, please ask.)

char c = funTest().a[0]; /* valid, initialises c with 'H' */
char *p = funTest().a; /* valid, initialised p with a pointer value */
c = *p; /* invalid, accessing the function call's result after the
next sequence point */

funTest().a[0] = 'H'; /* invalid, modifying function call's result */
Forgot to ask you one more question.
The left operand of assignment operator should be an Lvalue, but in
this case it is an rvalue, but the compiler doesn't complain that
"Lvalue required". So can I conclude that a structure containing an
array type returned by a function is converted from Rvalue to Lvalue!
(Really funny!!)
Or is it Compiler dependent?
Does the standard say anything about the value returned by, functions
returning structure containing array type?
I hope my question is clear.

Thanks in advance for the reply.
char str[100];
strcpy(str, funTest().a); /* invalid, accessing the function call's
result after the next sequence point */- Hide quoted text -

- Show quoted text -
 
G

Guest

Consider the following code:
#include <stdio.h>
#include <string.h>
struct test{
char a[100];
}
funTest( void );
int main( void )
{
printf("%s",funTest().a);
return 0;
}
struct test funTest()
{
struct test foo;
strcpy(foo.a,"Hello");
return foo;
}
[...]
char c = funTest().a[0]; /* valid, initialises c with 'H' */
char *p = funTest().a; /* valid, initialised p with a pointer value */
c = *p; /* invalid, accessing the function call's result after the
next sequence point */
funTest().a[0] = 'H'; /* invalid, modifying function call's result */
char str[100];
strcpy(str, funTest().a); /* invalid, accessing the function call's
result after the next sequence point */

Let us extend the topic. Is this the only case, when an rvalue of type
array is converted to rvalue of type pointer to the first element of
the array using temporary storage?

A structure that is not a function call's result must be an lvalue, as
far as I know. So yes, I believe this is the only special case.
 
G

Guest

funTest().a[0] = 'H'; /* invalid, modifying function call's result */

Forgot to ask you one more question.
The left operand of assignment operator should be an Lvalue, but in
this case it is an rvalue, but the compiler doesn't complain that
"Lvalue required". So can I conclude that a structure containing an
array type returned by a function is converted from Rvalue to Lvalue!

funTest().a[0] is short for *(funTest().a + 0).

funTest().a is an rvalue array, funTest().a + 0 is an rvalue pointer,
and *(funTest().a + 0) is a dereferenced pointer. Any dereferenced
pointer is an lvalue. There is no rvalue-to-lvalue conversion that
takes place.

The difference can matter:

struct S {
char m[1];
};
struct S s;
struct S f(void) {
return s;
}
int main(void) {
char *p;
p = s.m; /* valid */
p = (char *) &s.m; /* valid */
p = f().m; /* valid (but useless) */
p = (char *) &f().m; /* invalid */
}

The last statement is invalid because f().m is not an lvalue, so you
cannot apply to & operator to it. (The compiler I'm trying right now
disagrees with me; I might be wrong on this.)
 
C

Chris Torek

[regarding a function, in this case named "funTest", that returns
a structure "struct test", containing an array, in this case "a"]

Correct. [...]
The pointer points to a temporary, and accessing that temporary after
the next sequence point, or modifying it, results in undefined
behaviour. (If you don't know what a sequence point is, please ask.)

char c = funTest().a[0]; /* valid, initialises c with 'H' */

It is worth adding that this is new in C99. C89 never really
quite said enough about these things: we can make guesses, but
there is no wording in that standard to pin down the behavior.
In C89, even something like:

char c = funTest().a[0];

might not be valid. (One might hope that it *is* valid, with the
semantics required by C99, but I think it is dangerous to assume
so.) Note that:

struct test val;

val = funTest();

is valid in both C89 and C99, and is "safe way" to handle
structure-valued functions.
 
R

Rajesh S R

funTest().a[0] = 'H'; /* invalid, modifying function call's result */
Forgot to ask you one more question.
The left operand of assignment operator should be an Lvalue, but in
this case it is an rvalue, but the compiler doesn't complain that
"Lvalue required". So can I conclude that a structure containing an
array type returned by a function is converted from Rvalue to Lvalue!

funTest().a[0] is short for *(funTest().a + 0).

funTest().a is an rvalue array, funTest().a + 0 is an rvalue pointer,
and *(funTest().a + 0) is a dereferenced pointer. Any dereferenced
pointer is an lvalue. There is no rvalue-to-lvalue conversion that
takes place.

The difference can matter:

struct S {
    char m[1];};

struct S s;
struct S f(void) {
    return s;}

int main(void) {
    char *p;
    p = s.m; /* valid */
    p = (char *) &s.m; /* valid */
    p = f().m; /* valid (but useless) */
    p = (char *) &f().m; /* invalid */

}

The last statement is invalid because f().m is not an lvalue, so you
cannot apply to & operator to it. (The compiler I'm trying right now
disagrees with me; I might be wrong on this.)

Thanks, You are right.
My compiler Dev-CPP, gives Lvalue required error for the statement:
p = (char *) &f().m; /* invalid */

And I think it is even more "intelligent" enough to point out that the
statement:
p = f().m; /* valid (but useless) */
is useless and generates an error "invalid use of non-lvalue array"!

Now I modified the Code u gave:
#include <stdio.h>
struct S {
char m[1];


};


struct S s;
struct S f(void) {

return s;

}


int main(void) {
char *p;
printf("%s",(char*)f().m);/*Note Explicit casting to (char*) */



}

I know that I'm invoking UB by the following statement, if executed,:

printf("%s",(char*)f().m);/* Note Explicit casting to (char*) */

But the above statement is not compiling and gives an error:

"cannot convert to a pointer type"

But C standard guarantees that any pointer can be converted to (char*)
and back without causing any error or UB.
So I guess the assertion, "expression f().m is evaluated to yield an
rvalue pointer" is wrong and it remains as an rvalue array type only,
which is further clarified by the following code:


struct S {
char m[1];


};


struct S s;
struct S f(void) {

return s;

}


int main(void) {
char *p;
*(f().m+0) = 'a';/*Compiler complains*/



}

Compiler gives an error corresponding to the line:
*(f().m+0) = 'a';/*Compiler complains*/
The error is
"invalid operands to binary + "
which is possible only when f().m is an array type and not a pointer
type as we might think. So there is no conversion from array type to
pointer type here, *though C standard requires it*!

But, how the expression statement:
f().m[0] = 'a';
gets executed when f().m is not converted to pointer type?

Note that when we give statement like the following:

printf("%s",f().m);/* I am invoking a UB, but leave it! */

The compiler compiles without any error because printf() is a variable
argument function and there is no way to check the type of each
argument, though there is no possibility of passing an array as such
in C!(except in this case, I guess!)

Do reply about my comments and correct me if I'm wrong.
 
R

Rajesh S R

funTest().a[0] = 'H'; /* invalid, modifying function call's result */
Forgot to ask you one more question.
The left operand of assignment operator should be an Lvalue, but in
this case it is an rvalue, but the compiler doesn't complain that
"Lvalue required". So can I conclude that a structure containing an
array type returned by a function is converted from Rvalue to Lvalue!

funTest().a[0] is short for *(funTest().a + 0).

funTest().a is an rvalue array, funTest().a + 0 is an rvalue pointer,
and *(funTest().a + 0) is a dereferenced pointer. Any dereferenced
pointer is an lvalue. There is no rvalue-to-lvalue conversion that
takes place.

The difference can matter:

struct S {
    char m[1];};

struct S s;
struct S f(void) {
    return s;}

int main(void) {
    char *p;
    p = s.m; /* valid */
    p = (char *) &s.m; /* valid */
    p = f().m; /* valid (but useless) */
    p = (char *) &f().m; /* invalid */

}

The last statement is invalid because f().m is not an lvalue, so you
cannot apply to & operator to it. (The compiler I'm trying right now
disagrees with me; I might be wrong on this.)


Sorry, I forgot to mention an important thing.
I recently subscribed to this group and I gave my full name
Rajesh S R
for subscription, which is abbreviated as SRR in the above posts!
So dont get confused by the new name in the recent post!!

I know that, what I said just now might be irrelevant, but I dont want
to confuse people unnecessarily!!
 
G

Guest

Rajesh said:
funTest().a[0] = 'H'; /* invalid, modifying function call's result */
Forgot to ask you one more question.
The left operand of assignment operator should be an Lvalue, but in
this case it is an rvalue, but the compiler doesn't complain that
"Lvalue required". So can I conclude that a structure containing an
array type returned by a function is converted from Rvalue to Lvalue!

funTest().a[0] is short for *(funTest().a + 0).

funTest().a is an rvalue array, funTest().a + 0 is an rvalue pointer,
and *(funTest().a + 0) is a dereferenced pointer. Any dereferenced
pointer is an lvalue. There is no rvalue-to-lvalue conversion that
takes place.

The difference can matter:

struct S {
    char m[1];};

struct S s;
struct S f(void) {
    return s;}

int main(void) {
    char *p;
    p = s.m; /* valid */
    p = (char *) &s.m; /* valid */
    p = f().m; /* valid (but useless) */
    p = (char *) &f().m; /* invalid */

}

The last statement is invalid because f().m is not an lvalue, so you
cannot apply to & operator to it. (The compiler I'm trying right now
disagrees with me; I might be wrong on this.)

Thanks, You are right.
My compiler Dev-CPP, gives Lvalue required error for the statement:
p = (char *) &f().m; /* invalid */

And I think it is even more "intelligent" enough to point out that the
statement:
p = f().m; /* valid (but useless) */
is useless and generates an error "invalid use of non-lvalue array"!

Yes, I now see that too that I'm using GCC. It converts non-lvalue
arrays to pointers only in C99 mode (using the -std=c99 command-line
option). I missed that it's new in C99, but Chris Torek explained it
quite well. This also applies to the rest of your post.
 
C

CBFalconer

Rajesh said:
.... snip ...

Sorry, I forgot to mention an important thing. I recently
subscribed to this group and I gave my full name Rajesh S R
for subscription, which is abbreviated as SRR in the above posts!
So dont get confused by the new name in the recent post!!

There is no such thing as subscribing to this newsgroup. You may
have subscribed to some sort of Google service, which provides a
poor interface to the real Usenet system, which in turn existed
before Google was a gleam in its grandaddies eye.
 
Y

Yevgen Muntyan

CBFalconer said:
Rajesh S R wrote:
... snip ...

There is no such thing as subscribing to this newsgroup.

Yes there is. I do it all the time in mozilla ;)
You may
have subscribed to some sort of Google service, which provides a
poor interface to the real Usenet system, which in turn existed
before Google was a gleam in its grandaddies eye.

Why do people use 'google' as 'microsoft', even if google isn't
mentioned? Was it that bad?

Yevgen
 
O

Old Wolf

There is no such thing as subscribing to this newsgroup.

Can you clarify that? Every newsreader I've ever looked at
has had the option to subscribe to newsgroups.
 
R

Rajesh S R

[regarding a function, in this case named "funTest", that returns
a structure "struct test", containing an array, in this case "a"]

Harald van Dijk said:
Correct. [...]
The pointer points to a temporary, and accessing that temporary after
the next sequence point, or modifying it, results in undefined
behaviour. (If you don't know what a sequence point is, please ask.)
char c = funTest().a[0]; /* valid, initialises c with 'H' */

It is worth adding that this is new in C99. C89 never really
quite said enough about these things: we can make guesses, but
there is no wording in that standard to pin down the behavior.
In C89, even something like:

char c = funTest().a[0];

might not be valid. (One might hope that it *is* valid, with the
semantics required by C99, but I think it is dangerous to assume
so.)

*This is what I follow from yor reply:*

So do you mean to say that result of trying to access an rvalue array,
is implementation dependent as the standard does not say anything
about Rvalue array, but describes about array type which implicitly
means an Lvalue array type, I guess.
So the implementation dependency of Rvalue array access, cleary points
the implementation dependency of the following code:

struct S {
char m[1];



};


struct S s;
struct S f(void) {

return s;



}


int main(void) {
char a;
a = *(f().m+0);/*Compiler complains*/


}
I guess any other compiler may or may not complain about it.


But if I modify the main() function to the following:
int main(void) {
char a;
a = f().m[0];/*Does'nt complain*/

}
There's no error generated by my compiler, even when I compile it
using -ansi and -std=C99.
But some other compiler might complain about it.Am I right?

Did I interpret what you said correctly?
Please comment about my statements and clarify my doubts.
Thanks in advance for the reply.
 
C

Chris Torek

[regarding array rvalues, which arise only from functions returning
structures that have as one of their members an array]
It is worth adding that [well-defined behavior for array rvalues, provided the usage is well-enough contained,]
is new in C99. ...

*This is what I follow from yor reply:*

So do you mean to say that result of trying to access an rvalue array,
is implementation dependent as the standard does not say anything
about Rvalue array, but describes about array type which implicitly
means an Lvalue array type, I guess.

For C89, pretty much, yes.
But if I modify the main() function to the following:
int main(void) {
char a;
a = f().m[0];/*Does'nt complain*/

}
There's no error generated by my compiler, even when I compile it
using -ansi and -std=C99.

I assume you mean you tried once with "-ansi", and one other time
with "-std=c99" (since -ansi, in newer versions of gcc, means
"-std=c89"). (You should also add "-pedantic", in both cases, to
get gcc to print diagnostics for GNU-specific extensions.)
But some other compiler might complain about it.Am I right?

It might or might not complain; the biggest danger is that it might
generate code that fails in "interesting" ways. For instance, the
code might work when tested (i.e., when run with test data), but
fail -- at worst, quietly produce wrong answers -- when put into
actual use on valuable input data.
 
R

Rajesh S R

[regarding array rvalues, which arise only from functions returning
structures that have as one of their members an array]
It is worth adding that [well-defined behavior for array rvalues,

provided the usage is well-enough contained,]

Rajesh S R said:
*This is what I follow from yor reply:*
So do you mean to say that result of trying to access an rvalue array,
is implementation dependent as the standard does not say anything
about Rvalue array, but describes about array type which implicitly
means an Lvalue array type, I guess.

For C89, pretty much, yes.
But if I modify the main() function to the following:
int main(void) {
char a;
a = f().m[0];/*Does'nt complain*/
}
There's no error generated by my compiler, even when I compile it
using -ansi and -std=C99.

I assume you mean you tried once with "-ansi", and one other time
with "-std=c99" (since -ansi, in newer versions of gcc, means
"-std=c89"). (You should also add "-pedantic", in both cases, to
get gcc to print diagnostics for GNU-specific extensions.)
But some other compiler might complain about it.Am I right?

It might or might not complain; the biggest danger is that it might
generate code that fails in "interesting" ways. For instance, the
code might work when tested (i.e., when run with test data), but
fail -- at worst, quietly produce wrong answers -- when put into
actual use on valuable input data.

Thanks for your reply.

So do you mean to state that since Ansi standard says nothing abour
rvalue type array, am I invoking undefined behavior, and *not*
implementation-defined behavior?

And a generic question will be:-
If Ansi standard does'nt say anything about something, is the behavior
implementation defined or undefined or any other behavior?
If any other behavior, please specify what.

Thanks in advance for the reply.
 
F

Flash Gordon

Rajesh S R wrote, On 13/03/07 13:09:

And a generic question will be:-
If Ansi standard does'nt say anything about something, is the behavior
implementation defined or undefined or any other behavior?
If any other behavior, please specify what.

The C standards explicitly state that if the behaviour is not defined by
the standard then it is undefined behaviour exactly the same as if it
explicitly said it was undefined behaviour.

ISO is the international standard body, ANSI is mainly relevant to the
USA and the original publication of the standard in 1989 before ISO
adopted it.
Thanks in advance for the reply.

Please don't quote peoples signatures, i.e. the bit I left in above that
you quoted, unless you are actually commenting on them.
 
S

santosh

Rajesh said:
[regarding array rvalues, which arise only from functions returning
structures that have as one of their members an array]
It is worth adding that [well-defined behavior for array rvalues,

provided the usage is well-enough contained,]
is new in C99. ...

Rajesh S R said:
*This is what I follow from yor reply:*
So do you mean to say that result of trying to access an rvalue array,
is implementation dependent as the standard does not say anything
about Rvalue array, but describes about array type which implicitly
means an Lvalue array type, I guess.

For C89, pretty much, yes.
But if I modify the main() function to the following:
int main(void) {
char a;
a = f().m[0];/*Does'nt complain*/
}
There's no error generated by my compiler, even when I compile it
using -ansi and -std=C99.

I assume you mean you tried once with "-ansi", and one other time
with "-std=c99" (since -ansi, in newer versions of gcc, means
"-std=c89"). (You should also add "-pedantic", in both cases, to
get gcc to print diagnostics for GNU-specific extensions.)
But some other compiler might complain about it.Am I right?

It might or might not complain; the biggest danger is that it might
generate code that fails in "interesting" ways. For instance, the
code might work when tested (i.e., when run with test data), but
fail -- at worst, quietly produce wrong answers -- when put into
actual use on valuable input data.

Thanks for your reply.

So do you mean to state that since Ansi standard says nothing abour
rvalue type array, am I invoking undefined behavior, and *not*
implementation-defined behavior?

I think it's behaviour that's unspecified by omission. A conforming
implementation *must* document it's choice for behaviour defined in
the Standard as implementation dependant. However that's not required
for undefined and unspecified behaviour.
And a generic question will be:-
If Ansi standard does'nt say anything about something, is the behavior
implementation defined or undefined or any other behavior?
If any other behavior, please specify what.

If it doesn't say anything about something then that's unspecified by
omission. Otherwise it's either explicitly mentioned as unspecified,
undefined, implementation defined or defined.
Thanks in advance for the reply.

Note also that a lot of Defect Reports and their responses have been
published by the Standards committee. Not all of them are incorporated
in the latest Standard or draft document. They're however available at
WG14's website. Some of these Defect Reports may define or better
elucidate material left unspecified by omission in the actual Standard.
 
F

Flash Gordon

santosh wrote, On 13/03/07 15:07:
Rajesh S R wrote:


If it doesn't say anything about something then that's unspecified by
omission. Otherwise it's either explicitly mentioned as unspecified,
undefined, implementation defined or defined.

No, anything undefined by omission is UNDEFINED. I.e. it can make
daemons fly out of your nose. Read the definition of Undefined Behaviour
in n1124.pdf, you can find a pointer to it on http://clc-wiki.net/
Note also that a lot of Defect Reports and their responses have been
published by the Standards committee. Not all of them are incorporated
in the latest Standard or draft document. They're however available at
WG14's website. Some of these Defect Reports may define or better
elucidate material left unspecified by omission in the actual Standard.

Links to this and other useful stuff are also on http://clc-wiki.net/
under the standardisation section.
 
S

santosh

Flash said:
santosh wrote, On 13/03/07 15:07:

No, anything undefined by omission is UNDEFINED. I.e. it can make
daemons fly out of your nose. Read the definition of Undefined Behaviour
in n1124.pdf, you can find a pointer to it on http://clc-wiki.net/

I see your point. Anything unspecified by omission, though not
explicitly mentioned as undefined behaviour, must be taken as such,
since the Standard, by failing to elaborate, imposes no requirement on
the implementation, one way or the other.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,157
Latest member
MercedesE4
Top