Must casting destroy lvalueness?

David desJardins desj at brahms
Thu Oct 23 21:01:44 AEST 1986

In article <4617 at brl-smoke.ARPA>, NET-RELAY.ARPA>@brl-smoke.ARPA writes:
>                     For example, a useful and readable way to move a pointer 
> through a buffer containing a mixture of objects of different sizes is 
>                        ((OBJECT)pointer)++

In article <252 at BMS-AT.UUCP> stuart at BMS-AT.UUCP (Stuart D. Gathman) writes:
>A more correct syntax:
>  char *pointer;
>  /* . . . */
>  pointer += sizeof (OBJECT);
>  /* . . . */
>And clearer to boot if you ask me.

   Wrong if you ask me.  First, in the original example it is clear that
OBJECT is a pointer type.  And second, your sample code does not work, and
can not readily be fixed, if sizeof (char) != 1.

In article <657 at dg_rtp.UUCP> throopw at dg_rtp.UUCP (Wayne Throop) writes:
>I sayeth that if thou wishest to taketh an object as a different typeth,
>thou mayest do so.  However, casts are not the way to do this in C, and
>the practice is not portable.  If you must take the bits of one pointer
>type as being those of another pointer type, use
>                (*((some_type **)&p))++

   In C, pointers and lvalues are the same thing (there is a bijection given
by & and *).  Essentially, = (and the other assignment operators) automatic-
ally take the address of their left-hand arguments, in much the same way that
setq/set! quote their first arguments.  In both cases this is done simply to
enhance readability and reduce mistakes; x = x+1 is clearer and less error-
prone than &x <- x+1 would be [store x+1 in the location &x], just as
(setq x (+ x 1)) is clearer and less error-prone than (set (quote x) (+ x 1)).
   Without this syntactic sugar, the situation would be clearer.  The C
statement (foo) x = ... can correspond either to &((foo) x) <- ... or to
(foo *) (&x) <- ..., depending on when the implicit address calculation takes
place.  Since only the latter makes any real sense, I submit that casting of
lvalues should be interpreted in this way.
   So I would conclude that the statement ((OBJECT) pointer)++ should be
interpreted as

	* ((OBJECT *) &pointer) = (OBJECT) pointer + 1;

It is not absolutely clear that this is equivalent to Wayne Throop's
alternative formulation (* ((OBJECT *) &pointer))++, which would give

	* ((OBJECT *) &pointer) = * ((OBJECT *) &pointer) + 1;

or to the standard C construction for this type of operation, which is

	pointer = (char *) ((OBJECT) pointer + 1);

But in any implementation in which casting of pointers works at all, I think
that these should almost certainly give the same result.  At any rate they
are all legal C.

>or use unions like God intended.  Don't try to pervert casts to do
>something they weren't intended for.  Casts convert, unions take-as.
>The take-as operation is inherently non-portable.

   But the point is that casts of pointers *don't* convert.  Either they
simply take-as, or they are meaningless.  So, if the language allows casting
of pointers, then I see no valid reason to complain when the programmer uses
this feature (especially since essentially all C implementations make it
impossible to avoid when using any sort of dynamic memory allocation!).
   And if he is allowed to use casting, why force him to write *((foo *) &x) =
when (foo) x = will do?  At any rate, I think that the answer to the question
"*Must* casting destroy lvalues?" is clearly "No."

   -- David desJardins

More information about the Comp.lang.c mailing list