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 */ ------