[net.lang.c] Must casting destroy lvalueness?

throopw@dg_rtp.UUCP (Wayne Throop) (10/21/86)

> NET-RELAY.ARPA>@brl-smoke.ARPA (Scott)

> I'm relatively new to info-c and don't know if you've had this debate
> so just banish me to the archive if you have.

It has come around before.

> C pedants claim that casting destroys lvalueness.  Their argument is
> essentially that they can imagine a machine on which casting forces
> the use of a temp so lvalueness is gone.

Not that they can imagine such a machine.  That such machines actually
exist.  I am editing on one now.

> C users, on the other hand, find they have to program real machines not
> hypothetical ones and that almost all of these real machines don't use a 
> temp when casting.  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)++
>
> This construct is disallowed by Harbison's compiler. 

Not really very readible.  Let's take a similar example.  Would you
expect

        int i;
        ((short)i)++;

to do anything sensible?  If so, why?  If not, why should the pointer
case work sensibly?  After all, there *are* machines upon which integers
and shorts "mean the same thing", so the cast and increment could work
sometimes, right?

> I fear that the C standards committee is going to take away such practical 
> constructs and turn production quality C compilers into academic quality 
> ones.  Who knows, there may develop a brisk business in C compilers that 
> promise NOT to be standard conforming.

Only among those who don't care about portability or maintainability.

> How sayeth the C standard committee?  How sayeth the users?

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))++

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.

--
"Thank you for your support."
-- 
Wayne Throop      <the-known-world>!mcnc!rti-sel!dg_rtp!throopw

NET-RELAY.ARPA>@brl-smoke.ARPA (10/21/86)

I'm relatively new to info-c and don't know if you've had this debate
so just banish me to the archive if you have.

C pedants claim that casting destroys lvalueness.  Their argument is
essentially that they can imagine a machine on which casting forces
the use of a temp so lvalueness is gone.

C users, on the other hand, find they have to program real machines not
hypothetical ones and that almost all of these real machines don't use a 
temp when casting.  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)++

This construct is disallowed by Harbison's compiler. 

I fear that the C standards committee is going to take away such practical 
constructs and turn production quality C compilers into academic quality 
ones.  Who knows, there may develop a brisk business in C compilers that 
promise NOT to be standard conforming.

How sayeth the C standard committee?  How sayeth the users?

                                                        Regards, Scott

"You can hack any formalism so why not have useful formalisms?"

stuart@BMS-AT.UUCP (Stuart D. Gathman) (10/21/86)

In article <4617@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)++

A more correct syntax:

{
  char *pointer;
  /* . . . */
  pointer += sizeof (OBJECT);
  /* . . . */
}

And clearer to boot if you ask me.
-- 
Stuart D. Gathman	<..!seismo!{vrdxhq|dgis}!BMS-AT!stuart>

desj@brahms (David desJardins) (10/23/86)

In article <4617@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@BMS-AT.UUCP> stuart@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@dg_rtp.UUCP> throopw@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

stephen@datacube.UUCP (10/23/86)

I generally use or define caddr_t as the type of a generic pointer, and then
use macros to perform the indicated operations, i.e.:

caddr_t generic_pointer;

#define DATA( p, type ) (*((type *)(p)))
#define SUCC( p, type ) ((p) += sizeof(type))
#define PRED( p, type ) ((p) -= sizeof(type))

a = DATA(p,int);
SUCC(a, int);
b = DATA(p,double);
SUCC(p, double);

In the case of a compiler where the cast in DATA is invalid, an 
alternate formulation can be made.


Stephen Watkins                    UUCP: ihnp4!datacube!stephen
Datacube Inc.; 4 Dearborn Rd.; Peabody, Ma. 01960; 617-535-6644

desj@brahms (David desJardins) (10/24/86)

In article <657@dg_rtp.UUCP> throopw@dg_rtp.UUCP (Wayne Throop) writes:
>Let's take a similar example.  Would you expect
>
>        int i;
>        ((short)i)++;
>
>to do anything sensible?  If so, why?

   In my opinion this should have the result

	* ((short *) &i) = (short) i + 1;

Obviously the result of this operation is machine-dependent (since the effect
of casting int to short is machine-dependent).  But on an appropriate machine
this does indeed have not only a sensible but a *useful* effect -- it will
increment the low bytes of i without carrying into the high bytes.

   At any rate the casting of int to short performs a fundamentally different
operation than does casting of pointers (in Wayne's terminology, the former
"converts" and the latter "takes-as"), and so it is not necessary for one to
make sense in order for the other to be allowed.

   Note also that on most machines the statements

	int *p;
	((int) p)++;

makes sense (it increments the address referenced by p by the addressing unit
of the machine).  In fact this is arguably the correct way to use the value
produced by 'sizeof';

	(int) p += sizeof (foo);

makes sense on any machine where 'sizeof' gives results in multiples of the
addressing unit of the machine, whereas the more common alternative

	p = (int *) ((char *) p + sizeof (foo));

is both clumsier and makes the unnecessary assumption that sizeof (char) == 1.


   Another justification for casting of lvalues is the case of register
variables.  In this case Wayne's alternative syntax doesn't work:

	register int *p;
	(* ((foo **) &p))++;		<== ERROR

But the idea of casting (or "taking-as") the pointer p as a pointer to foo is
still perfectly valid, and the proposed syntax

	((foo *) p)++;

still makes sense, and can be understood and implemented by a compiler.

   -- David desJardins

blarson@usc-oberon.UUCP (Bob Larson) (10/25/86)

In article <55@cartan.Berkeley.EDU> desj@brahms (David desJardins) writes:

[some stuff so wrong that I decided to reply]

>In article <4617@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)++

Here is a major misconseption, based on a limited set of machines and a
limited imagination:
>   But the point is that casts of pointers *don't* convert.  

Repeat until remembered:

	CASTS DO ANY NESSISARY CONVERSION.

There are machines with more than one type of pointer.  C makes no
assuptions that require there only to be one type of pointer.
"Byte" pointers on a PDP-10 include both the bit position and size of
the object being pointed to.  There are quite a few machines with
different "word" and "character" pointers.

To do what the original poster wanted (as portably as possible):

	(pointer = (type_of_pointer) ((char *)pointer + sizeof(OBJECT)))

It says what you mean.  It is no more ugly than what you are trying to
do.  The explicit casts are obvious places to look for portablility
problems.  

[ If casts did not implicitly lose the lvalueness of the expression,
can you tell me what the following code fragment should do? Please
explain in terms the begining C programer who meant f += (float)i;
could understand, as well as the non-portable C coder who means 
*(int *)&f = i;

	float f = 0.1;
	int i = 2;
	(int)f += i;
]
-- 
Bob Larson
Arpa: Blarson@Usc-Eclb.Arpa	or	blarson@usc-oberon.arpa
Uucp: (ihnp4,hplabs,tektronix)!sdcrdcf!usc-oberon!blarson

throopw@dg_rtp.UUCP (Wayne Throop) (10/28/86)

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@brahms (David desJardins)
>> throopw@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

chris@umcp-cs.UUCP (Chris Torek) (10/29/86)

>In article <657@dg_rtp.UUCP> throopw@dg_rtp.UUCP (Wayne Throop) writes:
>>                (*((some_type **)&p))++

In article <55@cartan.Berkeley.EDU> desj@brahms (David desJardins) writes:
>... the point is that casts of pointers *don't* convert.

Yes they do, and Wayne Throop has to know it:  His machine does
indeed convert.  `char *' is 48 bits; `int *' is 32 bits.  DG
machines use word pointers, except when dealing with bytes.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu

gnu@hoptoad.uucp (John Gilmore) (10/29/86)

One interesting thing for people who don't understand this issue to do is
to ask yourself what the compiler should do for a construct like:

	int i = 17;
	((double)i)++;

Again, don't post your favorite answer to the net.  Just think about it.

PS:  When you're done that one, try:

	double i = 17;
	((int)i)++;
-- 
John Gilmore  {sun,ptsfa,lll-crg,ihnp4}!hoptoad!gnu   jgilmore@lll-crg.arpa
  Overheard at a funeral: "I know this may be an awkward time, but do
  you recall him ever mentioning source code?"		-- Charles Addams

desj@brahms (David desJardins) (10/30/86)

In article <4038@umcp-cs.UUCP> chris@umcp-cs.UUCP (Chris Torek) writes:
>In article <55@cartan.Berkeley.EDU> desj@brahms (David desJardins) writes:
>>... the point is that casts of pointers *don't* convert.
>
>Yes they do, and Wayne Throop has to know it:  His machine does
>indeed convert.  `char *' is 48 bits; `int *' is 32 bits.  DG
>machines use word pointers, except when dealing with bytes.

   My apologies; I misspoke.  What I meant to say is that casts of pointers
refer to the same physical locations, although the representations of pointers
of different types may be different.

   -- David desJardins

john@uw-nsr.UUCP (John Sambrook) (10/31/86)

In article <144@cartan.Berkeley.EDU> desj@brahms (David desJardins) writes:
>In article <4038@umcp-cs.UUCP> chris@umcp-cs.UUCP (Chris Torek) writes:
>>In article <55@cartan.Berkeley.EDU> desj@brahms (David desJardins) writes:
>>>... the point is that casts of pointers *don't* convert.
>>
>>Yes they do, and Wayne Throop has to know it:  His machine does
>>indeed convert.  `char *' is 48 bits; `int *' is 32 bits.  DG
>>machines use word pointers, except when dealing with bytes.
>
>   My apologies; I misspoke.  What I meant to say is that casts of pointers
>refer to the same physical locations, although the representations of pointers
>of different types may be different.
>
>   -- David desJardins

Just a small correction.  On the MV series both types of pointers are
32 bits.  It is also true that character pointers have a different 
format than pointers to other types.  Casting from one type to the other
on the MV series requires a conversion.

-- 
John Sambrook                           Work: (206) 545-7433
University of Washington WD-12          Home: (206) 487-0180
Seattle, Washington  98195              UUCP: uw-beaver!uw-nsr!john

throopw@dg_rtp.UUCP (Wayne Throop) (11/04/86)

> desj@brahms (David desJardins)
>> throopw@dg_rtp.UUCP (Wayne Throop)

>>Let's take a similar example.  Would you expect
>>        int i;
>>        ((short)i)++;
>>to do anything sensible?  If so, why?
>    In my opinion this should have the result
>         * ((short *) &i) = (short) i + 1;

"Opinion." OK.  Fine.  But David's opinion clearly and trivially differs
from that of the folks who designed and implemented the C language.  In
particular, David's interpretation of casts has them sometimes
converting, and sometimes taking-as.  K&R, H&S, and the draft X3J11
standard are all as clear as they can be... casts *ALWAYS* convert.

> Obviously the result of this operation is machine-dependent (since the effect
> of casting int to short is machine-dependent).

Casting is *NOT* machine dependent in anywhere near the same sense that
taking the bits of an integer as if they were a short is.  Again, David
has a fundamental misunderstanding of what it is that a cast does.  It
*ALWAYS* converts.  Casting an int to a short is machine dependant in
the limit, but in the case where the two types share range, the result
is dependable and machine independant.  The draft X3J11 standard even
outlines some guarantees on what this range of portable casting is.

> But on an appropriate machine
> this does indeed have not only a sensible but a *useful* effect -- it will
> increment the low bytes of i without carrying into the high bytes.

Oh, please!  Just because some illegal construction can be made to do
something useful on some machine-or-other is no reason to attempt to
legislate it so.  Especially when this operation can be specified with
legal C constructs.

>    At any rate the casting of int to short performs a fundamentally different
> operation than does casting of pointers (in Wayne's terminology, the former
> "converts" and the latter "takes-as"), and so it is not necessary for one to
> make sense in order for the other to be allowed.

False, false, false!  Pointers have differing bit-wise formats, just as
arithmetic types do.  The common examples are the word-addressed
machines, where the byte or character address format differs from the
"natural" architectural pointer format.

> In fact this is arguably the correct way to use the value
> produced by 'sizeof';
>         (int) p += sizeof (foo);

One can argue it.  And anybody that did so would be wrong.  A pointer
taken-as an integer need not address in sizeof-unit-sized chunks.  In
fact, there are many machines where this is not the case.  Further,
there are machines where pointers aren't even the same *SIZE* as
integers.  Surely these two trivial, well-known facts should point out
some flaws in any such argument?

>    Another justification for casting of lvalues is the case of register
> variables.  In this case Wayne's alternative syntax doesn't work:
>         register int *p;
>         (* ((foo **) &p))++;            <== ERROR
> But the idea of casting (or "taking-as") the pointer p as a pointer to foo is
> still perfectly valid, and the proposed syntax
>         ((foo *) p)++;
> still makes sense, and can be understood and implemented by a compiler.

Rubbish.  David just argued in a previous note that casts retaining
lvalueness was justified because lvalues and addresses are "the same
thing".  Now he claims that register values further support this
ludicrous position, despite the fact that they are a counterexample to
his previous justification!!  Puhleeeze!


I'm trying hard to be civil here, honest I am, but really!  If somebody
wants to act like a C guru, it might help to learn some C first.  Get
this straight:  casts convert.  Unions take-as.  A cast of a pointer can
take-as the bits it points to, BUT NOT THE POINTER ITSELF!  The take-as
operation is completely machine dependant, and code using it is rendered
non-portable by this use.  This is trivial, basic stuff folks.  You
can't even *BEGIN* to understand C until you get *THIS* straight.

--
"Don't do this at home, kids..."
-- 
Wayne Throop      <the-known-world>!mcnc!rti-sel!dg_rtp!throopw

leichter@yale.UUCP (Jerry Leichter) (11/05/86)

All this has really gotten out of hand.  I've found I've wanted to use casts
as lvalues in exactly one situation:  Incrementing a pointer by an amount
that is NOT to be taken as a multiple of the size of the type pointed to.
A "common" - NONE of these are what I'd really want to call common, but I
HAVE run into them more than once - case is in a (machine dependent!) storage
allocator that wants to make sure of proper alignment.  This doesn't arise
in something like malloc, which wants a char * (void *, in ANSI C) anyway,
but in specialized applications.  For example, I need to allocate stuff out
of a large array.  The "stuff" will be of a known type - a struct whose last
element is a varying-length array - and will thus be varying in size.  The
begining of anything allocated must be on an even address.  So I have a pointer
to some big structure that I'd like to increment by 1.  Not 1*size of the
structure, but 1.  YES, THIS IS MACHINE DEPENDENT - I got tied down by such
a dependency when I cast the pointer to int to look at the bottom bit!

I can think of no particular use for casting of arbitrary lvalues, but in
situations as above, the following definition for a cast argument to op=
would be handy:

	(type)a op= b

	shall mean:

	a = (type)a op b

(except that a is only evaluated once).

Pre- and post-decrement and increment should work in the obvious way.  Note
that the type of (type)a op= b (and of ++(type)a, etc.) is the type of a,
NOT the type being cast to.

I can think of no real uses for this construct where "op" is anything but
"+" or "-".
							-- Jerry

lambert@mcvax.uucp (Lambert Meertens) (11/06/86)

I still don't get what is so fundamentally wrong with the following
*addition* to C, which it seems to me that desj@brahms (David desJardins)
is arguing for:

    A cast (T)E in a context where an lvalue is required
    stands for *(T *)&(E) and so is lawful if the latter
    would be allowed here.

For example, this would then make the following lawful:

    int i;
    char *p = (char *)&i;
    ++(int)*p;

At least, in `my' cc (BSD 4.3) everything works as expected if I

    #define Lcast(T,E) (*(T*)&(E))

and then use

    ++Lcast(int, *p);

(I don't know if this is allowed by the ANSI C draft.)  Note that I am not
particularly arguing in favour of this extension, the fact being that this
is one of the areas where I can live with current C.  But neither do I see
a reason to get upset about it.  It allows you to write pretty meaningless
things, but that is the case already for current casts.  One thing that is
certain is that it does not invalidate existing code.  Also, it seems
consistent to me with the design philosophy of C: start by putting some
very confusing things in (pointers vs. arrays, here pointers vs. lvalues),
then legitimate some of the most obvious unambiguous mistakes.

-- 

Lambert Meertens, CWI, Amsterdam; lambert@mcvax.UUCP