Must casting destroy lvalueness?

Wayne Throop throopw at dg_rtp.UUCP
Tue Oct 28 07:48:50 AEST 1986


David is very misinformed on this question.  It is apparently an easy
thing to do, since mis- and dis- information about casts and pointers in
C is so common.  Never fear, I'll point out, case by case, where he went
wrong.  :-)

> desj at brahms (David desJardins)
>> throopw at dg_rtp.UUCP (Wayne Throop)
>>> Stuart Gathman

>>>>                        ((OBJECT)pointer)++
>>>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.

True, true.  But ANSI is likely to decide that sizeof(char) MUST ALWAYS
BE one (and I think this is universally true on existing
implementations... if I'm wrong, somebody let me know).  The relevant
incantation from the draft standard (3.3.3.4):

    The sizeof operator yields the size (in bytes) of its operand, which
    may be an expression of the parenthesized name of a type.  [...]
    When aplied to an operand that has type char, unsigned char, or
    signed char, the result is 1.

In order to make Stuart's method work (since OBJECT is a pointer type,
as David correctly points out) one must (oddly enough) say:

        pointer += sizeof( *((OBJECT)0) );


Now, in his critique of my earlier posting, David falls into *really*
serious error, as follows:

>>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 *).

False.  The "&" operator does not work on bit fields nor register
values, and yet these are lvalues.  In fact, close reading of K&R, H&S,
and the draft ANSI standard make it clear that not all legal lvalues map
to legal pointer typed expressions (via &), nor do all legal pointer
typed expressions map to legal lvalues (via *).

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

Again, false, and for about the same reasons.  The notion of an
assignment operator implicitly quoting the assignee is nice, somewhat
elegant, and a familiar notion in LISP.  But don't be fooled, folks.  C
is not now and has never been LISP, and C does not have this simple,
elegant, unifying notion.  C has "lvalues" instead.

> [expansion of this misunderstanding of lvalue, omitted]
>    So I would conclude that the statement ((OBJECT) pointer)++ should be
> interpreted as
>         * ((OBJECT *) &pointer) = (OBJECT) pointer + 1;

And you would be wrong.

> [more discussion based on the misunderstanding of lvalue, omitted]
> At any rate they are all legal C.

It is important to note that the original construct, ((OBJECT)pointer)++
is *DEFINITELY* *NOT* legal C.  (It is not clear to me whether David is
claiming that it IS legal... in any case it is important to note that it
is NOT.)

>> [...] 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.

Absolutely wrong.  Casts *ALWAYS* convert.  Harbison and Steele say (on
page 152):

    The cast causes the operand value to be converted to the type named
    within the parentheses.  Any permissible conversion may be invoked
    by a cast expression.

The draft ANSI document says (3.3.4):

    Preceeding an expression by a parenthesized type name converts the
    value of the expression to the named type.

K&R say similar things in several places.  (I'll let y'all look those up
by y'selfs.)

Another problem in the above passage is that David seems to have a
serious case of "pointers is pointers" disease.  Pointers to different
types may (and often do) have *COMPLETELY* *DIFFERENT* bit-wise formats.
Thus, the notion of converting an (int *) typed pointer to a (char *)
typed pointer is hardly "meaningless".  On the DG MV architecture (to
randomly choose an example I'm modestly familiar with) these two pointer
types have the "ring field" in different locations, and one has an
indirect bit that the other lacks.  A pointer to a given word needs to
be *CONVERTED* *TO* *A* *DIFFERENT* *FORMAT* to be a pointer to the
first byte in that word.  This is just what casts were intended for
(first and foremost in the arithmetic types, but clearly useful and
necessary for pointers also).

David, I'm not sure who told you "casts of pointers don't convert".
Find whoever told you that base canard, and pummel some sense into the
miscreant, willya?  You have been severely misled.

> 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!).

Yes, casting is necessary to write a memory allocator in any even nearly
portable way.  *BUT*, casts are *STILL* conversions, *NOT*, *NOT*, *NOT*
taken-ases.

>    And if he is allowed to use casting, why force him to write *((foo *) &x) =
> when (foo) x = will do?

Granting the implicit hypothetical, no reason, of course.
But (foo)x *won't* do.

> At any rate, I think that the answer to the question
> "*Must* casting destroy lvalues?" is clearly "No."

Well, waxing philosophical, I agree.  That is, I rather expect that one
can come up with some consistent set of semantics that will give meaning
to the notion of a cast as an lvalue.  But it is well to keep in mind:
(deep breath, all together now) these semantics won't be *C* semantics.

--
"Pwease Mistew Game Wawden, ... can you teww me what season it WEAWWY is?"
"Why SOIT'NY, m'boy!  It's BASEBALL season!"
                                --- (Elmer and Bugs, of course)
-- 
Wayne Throop      <the-known-world>!mcnc!rti-sel!dg_rtp!throopw



More information about the Comp.lang.c mailing list