[net.lang.c] Casting Pointers

bpl@lzpfd.UUCP (01/25/84)

Recently I came across a problem in  C  which  I  wonder  if
somebody  out  there  in  netland  can  help me with.  I was
trying to copy a string on a 68000 in C, and to make it fast
I was trying (where possible) to do the transfers a longword
at a time.

No Problem, I said to myself, its easy: just  cast  the  two
pointers to be long pointers.  So I came up with:

	     *(long *)to++ = *(long *)from++;

Then I went to look at  page  49  of  the  White  Book,  and
realized  that  the  ++  and  casts assosciate from right to
left, which means it would only increment  the  pointers  by
one for each time through.

Well, still no problem, I thought: that's what brackets  are
for.  So I changed the line to:

	   *((long *)to)++ = *((long *)from++;

I decided to test it on the VAX first, rather than  download
it  to  the  68000.  So I tried to compile it with the 5.0 C
compiler.  "illegal lhs of assignment", it said.  So I tried
it  on  the  68000  cross compiler, also based on PCC.  This
time it compiled prefectly, and ran no problem.

The cause of the difference is the treatment of casting: the
5.0  VAX  C  compiler  assumes  that the result of casting a
pointer of one type to a pointer of another type is  not  an
lvalue, even though the original pointer was an lvalue.  The
68000 cross-compiler assumes that the  result  is  still  an
lvalue.

I have read the White Book, and it leaves me as confused  as
ever.   Can  anybody  out  there  tell  me which Compiler is
correct, or is it an  ambiguity  which  leaves  you  to  the
tender mercies of you local PCC hacker.

To avoid flames: yes,  I  know  what  I  am  doing  is  non-
portable.   I  am  not  trying to write portable code.  I am
trying to write a fast copy for a  68000.   I  have  checked
that the pointers are really word-aligned.

				Brendan Lynch
				(pegasus!lzpfd!bpl)

mab@bnl.UUCP (Michael A. Bloom) (01/29/84)

	To avoid flames: yes,  I  know  what  I  am  doing  is  non-
	portable.   I  am  not  trying to write portable code.  I am
	trying to write a fast copy for a  68000.   I  have  checked
	that the pointers are really word-aligned.

If this is the case, then you dont want casts.  I've noticed (while using
adb) that using casts generates calls to routines that will perform type
conversion, rather than the inline code you might expect.

	Michael Bloom

-- 

Michael A. Bloom	..!bnl!mab  or mcb@mit-mc.arpa or mab@bnl 

jack@hp-dcde.UUCP (01/30/84)

Mr. Bloom states that you don't want casts (in this case), because casts
generate calls to routines that will perform type conversion rather than
inline code.

Not on our 68000 C compiler!  One can certainly consider architectures
where (char *) is represented differently than (long *), but on a 68000
they're both just a 32-bit (or 24-bit) address.

The ultimate solution is for each user to check the output
of his own compiler, but any compiler that generates code for this
type cast on a 68000 is pretty dubious.


						-Jack Applin
						(hplabs!hp-dcd!jack)

tjt@kobold.UUCP (01/31/84)

Michael Bloom (..!bnl!mab) recommends avoiding casts since:

    I've noticed (while using adb) that using casts generates calls
    to routines that will perform type conversion, rather than the
    inline code you might expect.

On most 68000 systems (e.g. using the MIT port of PCC), a function call
is used for float-to-integer and integer-to-float type casts, but not
on integer-to-integer or integer-to-pointer casts.
-- 
	Tom Teixeira,  Massachusetts Computer Corporation.  Westford MA
	...!{ihnp4,harpo,decvax}!masscomp!tjt   (617) 692-6200 x275

grunwald@uiuccsb.UUCP (02/04/84)

#R:houxt:-35400:uiuccsb:9000011:000:1652
uiuccsb!grunwald    Feb  3 11:32:00 1984

If you want to generate a fast, non-portable copy for the 68000, include the
following lines as your copy routine:

copy(from,to,length)
register char	*from,		/* a5 */
		*to;		/* a4 */
register int	length;		/* d7 */
{
/*
 *	only handles even byte boundries
 */

	if (((int)from & 1 == 0) && ((int)to & 1 == 0)) {
	    asm("lplbl:	movl	a5@++,a4@++");
	    asm("	dbnz	d7,lplbl");
	}
	else do_it_yourself;
}

This generates the following using the MIT CC68. I assume that ints are 32
bits, otherwise you might need to cast the pointer to a long. If you're going
to write machine dependent code, you might as well do it so that its as fast
as possible. While I'm not one to push the use of really kludgy things like
the "asm" construct, I think that when you're doing what you are trying to
do, it's useful.
   In the 68010 (e.g. as in the new Sun stations), there is a two word buffer
that was specificially designed for instruction pairs like the above. You
don't do any fetching for the opcoodes and the speed improvement is pretty
good. Check out the 68010 instruction manual for more details. However, if
you don't use the MIT CC68 compiler, you better try running the above
through cc -S whatever.c and look at the register allocations, etc.

	.data
	.text
	.globl	copy
copy:
	link	a6,#-_F1
	moveml	#_S1,a6@(-_F1)
	movl	a6@(8),a5
	movl	a6@(12),a4
	movl	a6@(16),d7
| A1 = 20
	movl	a5,d0
	andl	#1,d0
	bne	.L13
	movl	a4,d0
	andl	#0,d0
	beq	.L13
lplbl:	movl	a5@++,a4@++
		dbnz	d7,lplbl
.L13:
	bra	.L12
.L12:	moveml	a6@(-_F1),#12416
	unlk	a6
	rts
_F1 = 12
_S1 = 12416
| M1 = 0
	.data

Dirk Grunwald
University of Illinois
... ! ihnp4 ! uiucdcs ! grunwald

pedz@smu.UUCP (02/12/84)

#R:houxt:-35400:smu:13800002:000:672
smu!pedz    Feb 11 18:49:00 1984

I am suprised at how long this note has been around without the
original question being answered.  That question being which compiler
is correct.  

On page 214 of K&R it states that an lvalue may be a list of items,
however it may not be a type casted item.  Since an lvalue must be on
the left side of an assignment statement, this makes the statement
illegal.  Thus the 68000 compiler is "incorrect" in accepting the
syntax.  

This only makes sense becuase the result of a type cast could easily
be a temporay value on the stack or in a register.  The fact that the
technique is highly system dependant is also a good reason to make it
illegal.

Perry
parsec!smu!pedz

cottrell@NBS-VMS.ARPA (COTTRELL, JAMES) (10/10/85)

/*
> Ah yes.  Casting pointers.  A favorite passtime for anyone ...

I myself would rather cast aspersions, spells, or plays.

> who uses an architecture where char *  has different format from int *

I don't know. Who does? Maybe someday they'll get a *real* computer.

> > All versions of "lint" that I know of complain when you say something like
> >
> >       (int *)(char *)0;

Hey, what we need is a `(lint *)' type! This will cast any expression
to a type that neither lint nor some guys will complain about.
 
> > since you're casting a pointer of one type to a pointer of another type
> > which is, in general, dangerous.

So is an architexure where all pointers are not the same size as ints.
Even if I were to kneel at the sacred alter of portability, there are all
those other jokers out there that don't know the difference. I propose
passing all parameters on the stack as H-Format Floating Point (that's
VAXish for all you heathens out there), a one size fits all approach.
(add an entire line of :-)'s to this paragraph except for the first line.)
 
> But-but-but... "casting a pointer of one type to a pointer of another
> type" is "in general, dangerous"?  You mean that constructs like
> 
>     foo_ptr = (foo_type *)malloc( sizeof( foo_type ) );
> 
> are "in general, dangerous"?    Say it ain't so!

Not fair. This is a *specific* example. Malloc is special.
 
> I'm not quite sure what Guy was asserting above, but I suspect that it
> all boils down to ...

... is RTFM. How many times do we have to have this discussion? Guy,
maybe you should write a book & make some real money on this stuff.
I'll even buy a copy of it myself.

	jim		cottrell@nbs
*/
------