[gnu.gcc] left-hand side cast

bbc@titan.rice.edu (11/03/88)

I just read about left-hand side casts in the Internals of GNU CC, and was
wondering how everyone else feels about them.  They seem odd to me, as if
most of their uniqueness from traditional casts won't often be used.
Rather, I feel that they would typically be used for clarity, as a
substitute for wrapping the whole right-hand side in parentheses and a cast.

As an example, with "char *a" as in the section 5.4:
    a = (char *)( some complicated expression containing many parens)
becomes
    (char *)a = some complicated expression containing many parens

I haven't used left-hand side casts, or gcc, and so this is all intuition.
Any comments from experienced users?  Apologies if this has already been
hashed.

	Ben Chase	bbc@rice.edu		Computer Science Dept.

jgm@k.gp.cs.cmu.edu (John Myers) (11/17/88)

"Casts as lvalues" is the one extension that I seriously object to.
The semantics are not obvious (I had to read the description in the
manual three times before I understood what was going on) and are
certainly not what the people who have asked for lvalue casts in
comp.lang.c were asking (which is good--they generally didn't know
what they were talking about anyway.)

The extension adds no power to the language, given the typeof
operator.

	(int)a = b

is the same as:

	(int) (a = (typeof a) (int) b)

After having looked at a piece of code that used this extension and
had also #ifdef's for compilers without this extension, I must say
that the traditional code is more readable.

(If anyone is interested, the other extension that I object to, but
not quite so strongly is "Arithmetic on void-pointers and function
pointers".  If someone is manipulating byte-sized quantities, they
should make it obvious by casting the pointers to char and back.  I'd
rather have the compiler yell at me when I try to manipulate a void
pointer--those buggers are SUPPOSED to be opaque.)

-- 
_.John G. Myers		Internet: John.Myers@cs.cmu.edu
			LoseNet:  ...!seismo!inhp4!wiscvm.wisc.edu!give!up
"The world is full of bozos.  Some of them even have PhD's in Computer Science"
-- 

blarson@skat.usc.edu (Bob Larson) (11/20/88)

They are a documented bug.  In very rare situations, they may be
used to eliminate a declared temporary by making your code less
readable and less portable.  (They always have the latter effects.)
-- 
Bob Larson	Arpa: Blarson@Ecla.Usc.Edu	blarson@skat.usc.edu
Uucp: {sdcrdcf,cit-vax}!oberon!skat!blarson
Prime mailing list:	info-prime-request%ais1@ecla.usc.edu
			oberon!ais1!info-prime-request

lewie@EE.ECN.PURDUE.EDU (Jeff Lewis) (11/23/88)

Re: left-hand side casts

First, the name is awkward, how 'bout we call 'em lvalue casts?
(where an lvalue is as described in the C book; roughly speaking,
something to which you can assign a value.)

But anyway, ...

> They are a documented bug.  In very rare situations, they may be
> used to eliminate a declared temporary by making your code less
> readable and less portable.  (They always have the latter effects.)

I'm not attempting to justify the addition of various non-standard
features to an implementation of a language, however I think the
lvalue cast is getting a bad rap here.

Say you needed to push arbitrary sized data onto a stack:

	int *sp, foo;
	short int *sp2, bar;
	unsigned char *sp3, biff;

	*sp++ = foo;
	sp2 = (short int *) sp;
	*sp2++ = bar;
	sp3 = (unsigned char *) sp2;
	*sp3++ = biff;
	sp = (int *) sp3;
	...

given lvalue casts:

	int *sp, foo;
	short int bar;
	unsigned char biff;

	*sp++ = foo;
	*((short int *) sp)++ = bar;
	*((unsigned char *) sp)++ = biff;

even better, much more direct and descriptive of what's going on:
(here caddr_t is used in the sense of any valid pointer type of
proper alignment for all values to be pushed on the stack)

	caddr_t sp;
	long int foo;
	short int bar;
	unsigned char biff;

	*((long int *) sp)++ = foo;
	*((short int *) sp)++ = bar;
	*((unsigned char *) sp)++ = biff;

Now, obviously this isn't the kind of thing you're going to code everyday,
but when, and if, you do, I find the lvalue cast much preferable to
the indirection induced by the unnecessary temporaries.

--Jeff Lewis (lewie@ee.ecn.purdue.edu, pur-ee!lewie)

david@sun.uucp (David DiGiacomo) (11/23/88)

In article <8811221620.AA25541@ee.ecn.purdue.edu> lewie@EE.ECN.PURDUE.EDU
(Jeff Lewis) writes:
>Say you needed to push arbitrary sized data onto a stack:
>
>	int *sp, foo;
>	short int *sp2, bar;
>	unsigned char *sp3, biff;
>
>	*sp++ = foo;
>	sp2 = (short int *) sp;
>	*sp2++ = bar;
>	sp3 = (unsigned char *) sp2;
>	*sp3++ = biff;
>	sp = (int *) sp3;
>	...

This is not a good example to support the use of lvalue casts.  Ordinary
rvalue casts will clean it up nicely.

#define	PUSH(sp, item) \
	(* (typeof (item) *) (sp) = (item), ((sp) += sizeof (item)))

	caddr_t sp;
	int foo;
	short int bar;
	unsigned char biff;

	PUSH(sp, foo);
	PUSH(sp, bar);
	PUSH(sp, biff);
	...

The poster you quoted was probably referring to something like

	(type) complicated_expression++ = item;

where it's undesirable to realize the complicated_expression twice.