Re: A89: Which is better?


[Prev][Next][Index][Thread]

Re: A89: Which is better?




Hi!

> I very strongly disagree with the idea of assembly being easier
> to read than C. I think it all depends on how you write your C.
> Good C is easy to read. Good assembly is somewhat difficult to
> read. Bad C is impossible to read. Bad assembly is worse.

Now, I will talk only about GOOD C code. Some straightforward
operations in ASM needs ugly typecasts in C. I think that typecasts
often leads to ugly-looking C code, but they are unavoidable.
Suppose for example that you need to call a ROM routine which
is located at absolute address $250000. In asm you will write

jsr $250000

but the only way you can do this in C is

((void(*)(void))0x250000)();

Now, I will be more radical, but only using a realistic example.
Suppose that you want to copy 3840 bytes of data from address 
"buffer" to address $4c00 (LCD memory), and suppose that you 
want to call TIOS built-in function memcpy for this task. You
know that this function is 618th entry in the TIOS jump table,
which starts on address $c8. In assembly, you should write 
(assuming no "includes"):

pea 3840		; this is shorter than move.l #3840,-(a7)
pea $4c00
pea buffer
move.l $c8,a0
move.l (a0,618*4),a0
jsr (a0)

I think that this is very clear. But note what you need to do
in C (this line will generate exactly the same code as assembly
program given above):

((void(*)(void*,void*,long))(*(long*)(*(long*)0xc8+618*4)))
((void*)0x4c00,buffer,3840);

which is not clear, or (a bit more compact):

(*(void(**)(void*,void*,long))(*(long*)0xc8+618*4))((void*)0x4c00,buffer,384
0);

which is even less clear.

You will say that you can simply use

memcpy((void*)0x4c00,buffer,3840)

But, you can do this only because "memcpy" is included in the
TIGCCLIB library. More precise, it principally defines

#define memcpy (*(void(**)(void*,void*,long))(*(long*)0xc8+618*4))

so you can do this. But, if you want to call anything which is
not defined in the library, you need to do very ugly typecasting,
which is an example of hard-to-read GOOD code.

Another example: in one my program, I need to relocate another
executable program, starting at "cptr", which is "plen" bytes
long. I used the following code:

for(eptr=pptr=(unsigned*)(cptr+plen-4);*pptr;pptr-=2);
while(pptr<eptr) offs=*++pptr,*(char**)(cptr+2+*++pptr)=cptr+2+offs;

Easy to read? No. But this is GOOD code, and very efficient. This
code just represents my minds when I thought about how to solve this
problem. So, this is not code dedicated to be cryptic. This is only
my way of solving this problem. This is so clear for me, but this is
write-only code. Try to read and understand this. Not impossible, but
not easy (of course, I never use such code when I teach C to my 
students).

You are talking about "Hello world"? OK, you should write

printf_xy(0,0,"Hello world!");

where printf_xy is defined in stdio.h. But, the preprocessor will
replace printf_xy with its REAL definition. Look how this statement
looks like after preprocessing, assuming that you use TI-GCC with
TIGCCLIB 2.0 (if you don't believe, use -E switch during compiling):

({char __s[200];((int(*)(char*,char*,...))(*((long*)(*((long*)0xC8)
+(0x53)*4))))(__s,"Hello world!");((void(*)(int,int,char*,int))
(*((long*)(*((long*)0xC8)+(0x1A9)*4))))(0,0,__s,4);});

OK, I will shut up now. Please, don't take this message seriously;
it is more for fun ;-)

Cheers,

Zeljko Juric