[comp.lang.c] union *func

evil@arcturus.UUCP (Wade Guthrie) (10/26/88)

Is the following code portable, strictly conforming, etc.
	a = function()->member;
as in something like the following (really simplified) code:

	union yowza
	{	int	i;
		float	f;
		char	*c;
	};

	union yowza *yikes() /* actually, I pass the type here */
	{
		static union yowza fubar;
		fubar.i = 6; /* and I make the assignment based on
				the type */
		return (&fubar);
	}

	main()
	{	union yowza *yikes();
		int j;
		. . .
		j = yikes()->i;
	}
It works on (shudder) a VAX running VMS, and for this reason, I
suspect it is not portable -- can anyone help?


Wade Guthrie
Rockwell International
Anaheim, CA

(Rockwell doesn't necessarily believe / stand by what I'm saying; how could
they when *I* don't even know what I'm talking about???)

chris@mimsy.UUCP (Chris Torek) (10/27/88)

In article <2205@arcturus> evil@arcturus.UUCP (Wade Guthrie) writes:
>Is the following code portable, strictly conforming, etc.
>	a = function()->member;
>as in something like the following (really simplified) code:
[deleted]

It is conforming, etc., if function() returns a pointer to a structure
or union and the `member' field corresponds to a member of that
structure or union.  Likewise,

	a = function().member;

is conforming, etc., if function() returns a structure or union and the
`member' field corresponds, etc., with one additional restriction: the
member must not be an array.

Nonetheless, the second form is another one of those things that
compilers have got wrong in the past; you are better off with

	lump = function();
	a = lump.member;
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

gwyn@smoke.BRL.MIL (Doug Gwyn ) (10/27/88)

In article <2205@arcturus> evil@arcturus.UUCP (Wade Guthrie) writes:
>Is the following code portable, strictly conforming, etc.
>	a = function()->member;

There are probably implementations that don't support this.
However, in ANSI C functions can return (rvalue) structures.
Since the function value is not an lvalue, neither will the
result of the member-of operator be an lvalue.  Thus,
	sfunc().member = a;
is invalid.  (There should be no such problem with structure
pointers and ->.)

maart@cs.vu.nl (Maarten Litmaath) (10/28/88)

In article <14172@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
\	a = function().member;
\
\is conforming, etc., if function() returns a structure or union and the
\`member' field corresponds, etc., with one additional restriction:
\the member must not be an array.
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Why?
-- 
George Bush:                          |Maarten Litmaath @ VU Amsterdam:
             Capt. Slip of the Tongue |maart@cs.vu.nl, mcvax!botter!maart

chris@mimsy.UUCP (Chris Torek) (10/28/88)

... and union func():

>In article <14172@mimsy.UUCP> I noted that
>>	a = function().member;
>>
>>is conforming, etc., if function() returns a structure or union and the
>>`member' field corresponds, etc., with one additional restriction:
>>the member must not be an array.

In article <1585@solo8.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) asks
why the restriction exists.  `function().member' above is used in an
rvalue context; as such, if the member is an array, this amounts to
taking the address of part of a structure or union valued function.
If, as is common in some compilers, the return value is in fact copied
into local temporary storage, it may not have an address.  In
particular, consider the following:

	struct arr {
		int arr[10];
	};
	struct arr fn();

	main() {
		int *p;

		p = &fn().arr[8];
		printf("fn 3,4 = %d,%d; p = %p\n", p[0], p[1], (void *)p);
	}

This might `want' to compile into something like this:

	main_:
		| {
		mov	fp,-(sp)	| make stack frame
		mov	sp,fp

		| int *p;
		sub	#2,sp		| make stack space for local `p'

		| fn()
		sub	#20,sp		| make room
		lea	(sp),r0		| address of return space
		call	fn_		| fn()
		lea	(sp),r0		| compute address of return value
		| & .arr[8]
		lea	16(r0),r0
		| p =
		mov	r0,-2(fp)	| store in p
		| ;
		add	#20,sp		| done with return value

		| p
		mov	-2(fp),r0	| noop, hope optimiser pulls it out
		mov	r0,-(sp)	| push p
		| p[1]
		mov	-2(fp),r0	| noop, hope optimiser pulls it out
		mov	2(r0),-(sp)	| push p[1]
		| p[0]
		mov	(r0),-(sp)	| push p[0]
		| "string"
		pea	S1		| push address of string
		| printf(...)
		call	printf_		| printf the various variables
		add	#8,sp		| fix stack

		| }
		mov	fp,sp		| undo frame
		mov	(sp)+,fp
		ret

There is a problem here: pushing p clobbered p[1]!

Anyway, it is legislated out, as is such stuff as

	struct arr fn();
	main() {
		fn().arr[2] = 3;
	}

(At least, I *hope* stuff like the latter is illegal, given that the
point of the original restriction above is to allow structure return
values to be done using invisible temporaries....)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

guido@cwi.nl (Guido van Rossum) (10/28/88)

In article <14201@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>In article <1585@solo8.cs.vu.nl> maart@cs.vu.nl (Maarten Litmaath) asks
>why the restriction exists.

Chris's original posting said that "v = func().a" is legal, unless a is
an array.  The reason was that C has no array assignment, not that
there's anything special with array members of structs returned by
functions.  A less confusing way to state the ruls is that "func().a" is
legal, but as an rvalue only.
--
Guido van Rossum, Centre for Mathematics and Computer Science (CWI), Amsterdam
guido@piring.cwi.nl or mcvax!piring!guido or guido%piring.cwi.nl@uunet.uu.net

lai@vedge.UUCP (David Lai) (10/29/88)

In article <2205@arcturus> evil@arcturus.UUCP (Wade Guthrie) writes:
>Is the following code portable, strictly conforming, etc.
>	a = function()->member;
>as in something like the following (really simplified) code:
>(proceeds to describe the union pointer of the function return type...)
>It works on (shudder) a VAX running VMS, and for this reason, I
>suspect it is not portable -- can anyone help?

It works on suns and hp-ux (sys V) machines also.  However I read
somewhere (Harbison & Steele):

	-> operator requires an object that is an lvalue
	a function call is NEVER an lvalue

So there is some discrepency here.  Anyone care to comment on what ANSI
says?
-- 
	"What is a DJ if he can't scratch?"  - Uncle Jamms Army
The views expressed are those of the author, and not of Visual Edge, nor Usenet.
David Lai (vedge!lai@larry.mcrcim.mcgill.edu || ...watmath!onfcanim!vedge!lai)

chris@mimsy.UUCP (Chris Torek) (10/30/88)

In article <1770@vedge.UUCP> lai@vedge.UUCP (David Lai) writes:
>... I read somewhere (Harbison & Steele):
>
>	-> operator requires an object that is an lvalue

This is false.  -> *produces* an lvalue (with the usual exceptions for
arrays); it does not *require* one.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

guido@cwi.nl (Guido van Rossum) (10/31/88)

In article <7686@boring.cwi.nl> I wrote:
>Chris's original posting said that "v = func().a" is legal, unless a is
>an array.  The reason was that C has no array assignment, not that
>there's anything special with array members of structs returned by
>functions.  A less confusing way to state the rules is that "func().a" is
>legal, but as an rvalue only.

I received a mail message stating that in fact *any* use of func().a is
illegal when a is an array member; the reason being that this use of an
array name requires conversion to a pointer to its first element, and of
course Chris has adequately explained why that should be illegal.

I suppose that it is thus even illegal to write something like
"v = func().a[0]", even though that would make perfect sense (all
Chris's examples showed cases where a's address or the address of some
element was actually saved).  I suppose it would be possible to change
various rules about pointers, arrays, rvalues and lvalues to fix this,
but nobody cared.
--
Guido van Rossum, Centre for Mathematics and Computer Science (CWI), Amsterdam
guido@piring.cwi.nl or mcvax!piring!guido or guido%piring.cwi.nl@uunet.uu.net

norvell@csri.toronto.edu (Theodore Stevens Norvell) (11/04/88)

In article <7689@boring.cwi.nl> guido@cwi.nl (Guido van Rossum) writes:
>In article <7686@boring.cwi.nl> I wrote:
>>Chris's original posting said that "v = func().a" is legal, unless a is
>>an array.  
>
>I received a mail message stating that in fact *any* use of func().a is
>illegal when a is an array member; the reason being that this use of an
>array name requires conversion to a pointer to its first element, and of
>course Chris has adequately explained why that should be illegal.
>
>I suppose that it is thus even illegal to write something like
>"v = func().a[0]", even though that would make perfect sense (all
>Chris's examples showed cases where a's address or the address of some
>element was actually saved).  I suppose it would be possible to change
>various rules about pointers, arrays, rvalues and lvalues to fix this,
>but nobody cared.

[I presume you mean ``nobody cared to do so'', or, to put it more
positively, that the commttee cared that the indexing rules were simple
and uniform. :-)]

Yes.  func().a[0] is not legal.  The problem with it is that the proposed
standard defines array indexing in terms of addresses.  The example is
equivalent to *(func().a + 0) where func().a is the address of the first
element of the array.  But, as the array (being a member of an rvalue)
does not have an address, it does not make sense (even though it is clear
what is meant).

It is still not clear to me that func().a itself is illegal, though it
is clear that its use is limited.  Perhaps someone who knows the proposed
standard intimately would care to comment on whether, for example,
	sizeof( func().a )
is legal. Note that, contrary to the mail message Guido recieved, in ANSI C,
arrays arguments to sizeof are not coerced to pointers.  If func().a is not
legal can someone explain exactly why.


Theodore Norvell
norvell@csri.utoronto
utzoo!utcsri!norvell