[comp.sys.amiga] Portable "C" Code

kim@amdahl.UUCP (04/02/87)

[ For all you do ... this line's for you ... ]

I'm posting this for Robert Mitchell here at Amdahl.  I've run
into similar problems, but never really organized my thoughts
on the subject.  Seems like a topic worthy of some discussion
here on the net.  Note that I'm NOT cross-posting this to comp.lang.c
since we're talking about dealing with two specific Amiga compilers,
and not writing portable code in general.

/kim


From Robert Mitchell:

    Leo Schwab is one of the most creative and productive
    people on the net.  I really like what he did with
    ROBOTROFF.
     
    Converting it to Lattice, however, was painful.
    Porting software between compilers within the Amiga
    architecture can be (relatively) easy if authors
    follow some basic guidelines.
    There seem to be two primary problems in the Manx-to-Lattice
    (or vice-versa) translation:
     
      1) Manx defaults to 16 bit integers and Lattice uses 32 bit.
      2) Assembly language subroutines in Manx expect 16 bit
         integer parameters, while Lattice promotes to 32 bit.
     
    Use of the following conventions would make porting (and debugging)
    MUCH easier:
     
      1) Do not type functions as returning "void *".  Not
         only do we lose compiler type checking, it makes it
         harder for us Amiga novices to understand the code.
     
      2) Amiga data structures frequently use "UWORD" types
         for unsigned 16 bit integers.  NEVER cast these as (int);
         use (short) for math computations.  This guarantees
         sign extension for fields like "spr.x" which is "UWORD".
         Why unsigned integers contain negative numbers
         is an area I have not explored.
     
      3) Be extremely careful about type matching when using
         call by reference; the compiler can not help.
         "startxy(&spr.x,&spr.y)"  causes memory overlays
         when the function declares these as integers.
     
      4) Assembly language subroutines will always take some
         re-write because of the parameter passing differences.
         It would be preferable to code functions such as
         "rnd.asm" in "C", even at the cost of execution time.
         It would then port nicely.
     
      5) It would help a lot to get rid of excess warning messages
         by typing local subroutines with no return codes as "static void".
         This also cuts down on the number of external labels.
         This one is just my bias, and is not directly related
         to porting.
     
    I hope this is of some use.  I am certainly not finding fault
    with contributed software, and these reflect only my opinions.
     
    Robert Mitchell
    (408) 746-8491


-- 
UUCP:  kim@amdahl.amdahl.com
  or:  {sun,decwrl,hplabs,pyramid,ihnp4,seismo,oliveb,cbosgd}!amdahl!kim
DDD:   408-746-8462
USPS:  Amdahl Corp.  M/S 249,  1250 E. Arques Av,  Sunnyvale, CA 94086
CIS:   76535,25

[  Any thoughts or opinions which may or may not have been expressed  ]
[  herein are my own.  They are not necessarily those of my employer. ]

dillon@CORY.BERKELEY.EDU.UUCP (04/02/87)

	I now have both Lattice and Aztec C, and I've found that it's virtually
impossible to write code compatible with both and still be able to write 
efficiently.  Personally, I now use Aztec almost exclusively (Thanks Jim!),
and even though I always use the +L option for 32 bit ints, my code would
still require quite a bit of hacking of the header files before one could
get it to work with Lattice.  In fact, even Aztec users would have to do
some hacking to be able to compile it since I use a very automated 
enviroment (have cc and ln aliased, etc...).

	This is one of the reasons why I've stopped posting source for 
programs such as DME.... I have no desire to spend 12 hours making it work
on other peoples compiler enviroments, or even to standardize it to a
generic enviroment.  I rely heavily on my shell and the existance of
certain control files (my 'standard' enviroment) when working on a program.

	BTW, the source is *still* available on request if anybody's 
interested.  Also, I've noticed that 32 bit ints don't really increase
code size all that much.  What really makes the difference is the small
code and data model (using relative address for globals).

					-Matt

ewhac@well.UUCP (04/04/87)

In article <6082@amdahl.UUCP> kim@amdahl.UUCP (really Robert Mitchell) writes:
>
>[ For all you do ... this line's for you ... ]
>
>I'm posting this for Robert Mitchell here at Amdahl.  [ ... ]
>
>From Robert Mitchell:
>
	At last.  Some comments on the quality of my code.  I've been
interested to know this for some time.  While I appreciate the comments, I
thought you might equally be able to appreciate my perspective.

>    Leo Schwab is one of the most creative and productive
>    people on the net.  I really like what he did with
>    ROBOTROFF.
>     
>    Converting it to Lattice, however, was painful.

	I never said it wouldn't be.  Especially difficult should have been
_main.c, because of the fundamentally different startup code of the two
compilers.  I would be interested to know what *exactly* was required to
make Robotroff compiler and run under Lettuce.  I know the next statement is
terribly myopic, but the Manx code seemed relatively clean to me.

>    Porting software between compilers within the Amiga
>    architecture can be (relatively) easy if authors
>    follow some basic guidelines.
>    There seem to be two primary problems in the Manx-to-Lattice
>    (or vice-versa) translation:
>     
>      1) Manx defaults to 16 bit integers and Lattice uses 32 bit.
>      2) Assembly language subroutines in Manx expect 16 bit
>         integer parameters, while Lattice promotes to 32 bit.
>     
	Um... er...  Assembly, per se, doesn't *expect* anything.  I could
have supplied the random number generator I wrote for Lettuce and declared
it extern long, and it would have worked great (if I passed it a long).  I
should have called attention to this gotcha.

>    Use of the following conventions would make porting (and debugging)
>    MUCH easier:
>     
>      1) Do not type functions as returning "void *".  Not
>         only do we lose compiler type checking, it makes it
>         harder for us Amiga novices to understand the code.
>     
	Okay, I'll try.  I usually only type Amiga library functions as
returning either void * (if they return a pointer to anything), or long (if
they return an integral value of some sort).  Some might say, "Why not
#inlcude <functions.h>?"  Well, in the 3.20 version of the compiler, there
are ommisions and errors in that file (the exact nature of which I haven't
studied of late, but it is there).

	Also, I like having the type checking turned off, especially with
GetMsg().  GetMsg() almost never returns a struct Message *, but a struct
IntuiMessage *, or a struct IOStdReq *, etc.  Explicitly coercing the type
over to what it should be strikes *me personally* as rather painful, and
makes the code more difficult to read, adding more parenthesis and making it
look like a LISP program :-).

	I know, weak excuses, but that's what happens when you become rather
familiar with the operation of the processor and compiler, and you know what
you can get away with.  I suppose ANSI will visit me one day and ask me to
please stop that.

>      2) Amiga data structures frequently use "UWORD" types
>         for unsigned 16 bit integers.  NEVER cast these as (int);
>         use (short) for math computations.  This guarantees
>         sign extension for fields like "spr.x" which is "UWORD".
>         Why unsigned integers contain negative numbers
>         is an area I have not explored.
>     
	A very valid point.  Once again, an assumption on compiler behavior.
Sorry.

>      3) Be extremely careful about type matching when using
>         call by reference; the compiler can not help.
>         "startxy(&spr.x,&spr.y)"  causes memory overlays
>         when the function declares these as integers.
>     
	Erp.  Excuse me.  I'll be more careful.

>      4) Assembly language subroutines will always take some
>         re-write because of the parameter passing differences.
>         It would be preferable to code functions such as
>         "rnd.asm" in "C", even at the cost of execution time.
>         It would then port nicely.
>	  ^^^^^^^^^^^^^^^^^^^^^^^^^
	And if you believe that, I have a bridge to sell you :-) :-).

>      5) It would help a lot to get rid of excess warning messages
>         by typing local subroutines with no return codes as "static void".
>         This also cuts down on the number of external labels.
>         This one is just my bias, and is not directly related
>         to porting.
>     
	Hmm.  I like that one.  I'll try it.

>    I hope this is of some use.  I am certainly not finding fault
>    with contributed software, and these reflect only my opinions.
>     
>    Robert Mitchell
>    (408) 746-8491

	And your opinions are appreciated.  Really.  Anything I can do to be
a better programmer will be effort well-spent.  Thanks.

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 ________		 ___			Leo L. Schwab
	   \		/___--__		The Guy in The Cape
  ___  ___ /\		    ---##\		ihnp4!ptsfa!well!ewhac
      /   X  \_____    |  __ _---))			..or..
     /   /_\--    -----+==____\ // \  _		well ---\
___ (   o---+------------------O/   \/ \	dual ----> !unicom!ewhac
     \     /		    ___ \_  (`o )	hplabs -/       ("AE-wack")
 ____ \___/			     \_/
	      Recumbent Bikes:			"Work FOR?  I don't work FOR
	    The _O_n_l_y Way To Fly!		anybody!  I'm just having fun."

mwm@eris.UUCP (04/05/87)

In article <2865@well.UUCP> ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) writes:
>In article <6082@amdahl.UUCP> kim@amdahl.UUCP (really Robert Mitchell) writes:
>>      1) Manx defaults to 16 bit integers and Lattice uses 32 bit.
>>      2) Assembly language subroutines in Manx expect 16 bit
>>         integer parameters, while Lattice promotes to 32 bit.
>>     
>	Um... er...  Assembly, per se, doesn't *expect* anything.  I could
>have supplied the random number generator I wrote for Lettuce and declared
>it extern long, and it would have worked great (if I passed it a long).  I
>should have called attention to this gotcha.

Uh, is there anything wrong with using the supplied version of rand()
and srand() for your random number generator? They're ANSI standard,
so should run on anything. Of course, if you need a good PRN, you
might wanna check out your version first....

	Founder of the Committee to Reuse Code Everywhere,
	<mike
--
Here's a song about absolutely nothing.			Mike Meyer        
It's not about me, not about anyone else,		ucbvax!mwm        
Not about love, not about being young.			mwm@berkeley.edu  
Not about anything else, either.			mwm@ucbjade.BITNET

papa@bacall.UUCP (04/05/87)

> From Robert Mitchell:
> 
>     Leo Schwab is one of the most creative and productive
>     people on the net.  I really like what he did with
>     ROBOTROFF.
>      
>     Converting it to Lattice, however, was painful.
>     Porting software between compilers within the Amiga
>     architecture can be (relatively) easy if authors
>     follow some basic guidelines.
>     There seem to be two primary problems in the Manx-to-Lattice
>     (or vice-versa) translation:
>      
>       1) Manx defaults to 16 bit integers and Lattice uses 32 bit.
>       2) Assembly language subroutines in Manx expect 16 bit
>          integer parameters, while Lattice promotes to 32 bit.

This is not true.  What you call assembly language subroutines are actually
the Amiga library routines.  These have ALWAY expected 32 bits for their 
parameters.  So, no matter which compiler and model you use, you must pass
32-bit paramters to them.  There is never a problem when passing pointers,
since they are always 32-bits.  The problem comes when passing ints.  With
Lattice, all is easy since sizeof(int)=sizeof(long)= 32bits.  With MANX
it depends on the model used.  Using the model with 32-bit ints, one gets larger
code, but retains compatibility with Lattice.  Using the model with 16-bit ints,
one has to cast ints to longs when passing parameters to ROM kermel routines.
Also one has to add the letter L to EVERY constant that is passed, since by
default constants are of type int in C.

-- Marco Papa


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Marco Papa            3175 S. Hoover St., Ste. 275            (213)747-8498
                         Los Angeles, CA 90007           USC: (213)743-3752
                             F E L S I N A
Now working for                 :::::::                           BIX: papa
But in no way                   ::   ::
Officially representing         :::::::          ...!usc-oberon!bacall!papa
                            S O F T W A R E            papa@usc-cse.usc.edu
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

dillon@CORY.BERKELEY.EDU.UUCP (04/07/87)

      
>> From Robert Mitchell:
>>       1) Manx defaults to 16 bit integers and Lattice uses 32 bit.
>>       2) Assembly language subroutines in Manx expect 16 bit
>>          integer parameters, while Lattice promotes to 32 bit.
>
>This is not true.  What you call assembly language subroutines are actually
>the Amiga library routines.  These have ALWAY expected 32 bits for their 
>parameters.  So, no matter which compiler and model you use, you must pass
>32-bit paramters to them.  There is never a problem when passing pointers,
>since they are always 32-bits.  The problem comes when passing ints.  With
>-- Marco Papa

	You misinterpreted Robert's comment, Marco.  He was *NOT* talking
about the assembly interface to the Amiga library, he was talking about
assembly support routines that many people write for their programs.  Those 
people who are used to Manx w/16bit ints write their assembly routines 
expecting short's for int's on the stack whereas somebody writing assembly
for Lattice or Manx-32bit would always expect long's for ints on the stack.

				-Matt

papa@bacall.UUCP (04/08/87)

> 
>       
> >> From Robert Mitchell:
> >>       1) Manx defaults to 16 bit integers and Lattice uses 32 bit.
> >>       2) Assembly language subroutines in Manx expect 16 bit
> >>          integer parameters, while Lattice promotes to 32 bit.
> >
> >This is not true.  What you call assembly language subroutines are actually
> >the Amiga library routines.  These have ALWAY expected 32 bits for their 
> >parameters.  So, no matter which compiler and model you use, you must pass
> >32-bit paramters to them.  There is never a problem when passing pointers,
> >since they are always 32-bits.  The problem comes when passing ints.  With
> >-- Marco Papa
> 
> 	You misinterpreted Robert's comment, Marco.  He was *NOT* talking
> about the assembly interface to the Amiga library, he was talking about
> assembly support routines that many people write for their programs.  Those 
> people who are used to Manx w/16bit ints write their assembly routines 
> expecting short's for int's on the stack whereas somebody writing assembly
> for Lattice or Manx-32bit would always expect long's for ints on the stack.
> 
> 				-Matt

True and not true.  Robert says that "Assembly languages subroutines in
MANX expects 16 bit integers", and you are saying that this is true only
for people "who are used to MANX w/16bit" not "Manx-32bit". This was
basically my point.  Assembly language routines expect what you tell them
to expect.

Going back to "C" portability, Thomas Plum in his "Writing Portable C
Programs" tutorial at the USENIX 1986 conference gives the following
suggestions:

Some practical guarantees:
char	8 bits (or more)
short	16 bits (or more)
long	32 bits (or more)
int	no guarantee
use these types in preferences to int

-- Marco

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Marco Papa            3175 S. Hoover St., Ste. 275            (213)747-8498
                         Los Angeles, CA 90007           USC: (213)743-3752
                             F E L S I N A
Now working for                 :::::::                           BIX: papa
But in no way                   ::   ::
Officially representing         :::::::          ...!usc-oberon!bacall!papa
                            S O F T W A R E            papa@usc-cse.usc.edu
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

guilford@rpics.UUCP (04/10/87)

I've read several articles dealing with the incompatibilities between
lattice and manx C-compilers. This may be a naive question, but why is there
such an incompatibility? Isn't the purpose of a High-Level-Language to avoid
such problems.
I can understand that manx has a small memory model that passes small ints
to subroutines. It seems to me that as long as the entire program was
compiled by the same compiler, this should not matter unless one used one's
own assembler code. (It could also be a problem if one used 'int' and
assumed that it was long--but since C doesn't specify the size of int, one
should have used long anyways.)
The other source of problems would be in what subroutines are supplied and
possibly different reactions from the same subroutines in different versions.
The reason that I am asking this is that I am tired of fighting with this
incompatibility. I hate it when someone writes some nifty program, posts it
on the net (source only), and specifies that it should be compiled under
manx. I, however (regardless of whether this is good or bad) only have
lattice. I try to compile the silly thing there, and I get a couple of
screen fulls of errors. Now I can either try to hack the code to work, or
hope that the author is going to post the binary at some future time. This
seems to me to be a silly way to work.
What I am really wondering is if the sources of the incompatibilities are in
the above, fairly unavoidable, places, or whether the programmers are
writing in sleazy, non-portable ways that are geared to work with the quirks
of their favorite compiler (or is there some other incompatibility that I
haven't thought of?)?
I would think that people writing in C, using the starndard RKM routines
would produce portable code. Is it really that difficult?
I'm rather new at usenet, so I hope I haven't offended anyone.
--Jim Guilford
(guilford@csv.rpi.edu)

hsgj@batcomputer.UUCP (04/11/87)

In article <1102@rpics.RPI.EDU> guilford@rpics.RPI.EDU (Jim Guilford) writes:
>I've read several articles dealing with the incompatibilities between
>lattice and manx C-compilers. This may be a naive question, but why is there
>such an incompatibility? Isn't the purpose of a High-Level-Language to avoid
>such problems. [...good stuff...]
>I would think that people writing in C, using the starndard RKM routines
>would produce portable code. Is it really that difficult?
>
>--Jim Guilford
>(guilford@csv.rpi.edu)

I have never used Amiga Manx so this is written from a Lattice perspective.
I think a lot of compatibliity problems are (aside from RKM calling
conventions) the difference in the "standard" stdio packages on both
compilers.  I know that I just finished a routine that had to generate
-true- random numbers.  On every 4.2BSD cc I have used (under vax750,
gould,sequent) the function is called "random()" and it returns an integer
from 0 to MAXINT.  In Lattice C, a similar function is called "lrand48()"
and does the same thing but returns from 0 to MAXLONG.  Why the name
change?  Lattice also didn't like the way some of the string routines
were named and called some funny names, like "stccpy" for "strcpy".  Before
anyone flames, yes they do have a #define strcpy stccpy automatically so
you can still use strcpy.  Speaking of that, I believe someone said
that Manx has the "index" function, while Lattice uses "stptok" to
search for a substring.  Who is standard?  I don't know.  But anyways,
if your code relies on a lot of these idiosyncratically named functions,
then it probably won't port.
	Note that these are easy to fix with #ifdefs and #defines, but
only if you know that the problems exist.  One last comment:  Please
notice that I have avoided compiler wars.  Cash rewards accepted...
-- Dan Green
-- 
ARPA:  hsgj%vax2.ccs.cornell.edu@cu-arpa.cs.cornell.edu
UUCP:  ihnp4!cornell!batcomputer!hsgj   BITNET:  hsgj@cornella

mwm@eris.UUCP (04/11/87)

In article <659@batcomputer.tn.cornell.edu> hsgj@tcgould.tn.cornell.edu.UUCP (Dan Green) writes:
>In article <1102@rpics.RPI.EDU> guilford@rpics.RPI.EDU (Jim Guilford) writes:
>>I've read several articles dealing with the incompatibilities between
>>lattice and manx C-compilers. This may be a naive question, but why is there
>>such an incompatibility? Isn't the purpose of a High-Level-Language to avoid
>>such problems.

Foolish mortal! C is one of the most portable languages around, but
given two compilers from differen vendors, I can almost certainly
produce code that will compile with one and not the other. There's a
good chance I can also produce code that compiles on both, and gives
radically different results. ("Almost certainly" instead of
"certainly" because most Unix vendors use PCC as a base. That makes
things harder.)

>I have never used Amiga Manx so this is written from a Lattice perspective.

Ditto. However, I have worked with people with Manx compilers to
produce code that will compile/run under both.

>I think a lot of compatibliity problems are (aside from RKM calling
>conventions) the difference in the "standard" stdio packages on both
>compilers.

Yup. The other problem is that Manx makes an "int" 16 bits and Lattice
makes it 32 bits. Since "ints" is the default size for function
parameters & return values, things that aren't int's in those places
cause problems. This is the source of the "RKM calling conventions"
problems. Lattice people tend not to cast things (I'm guilty of that -
I use function prototypes, which serves the same purpose).

With Manx, code that passes non-int's without saying what's going on
tends to die horribly. If Manx supported function prototyping, this
problem wouldn't be so nasty. With Lattice, code broken as above tends
to work. Lattice, of course, support function prototyping. 

>I know that I just finished a routine that had to generate
>-true- random numbers.  On every 4.2BSD cc I have used (under vax750,
>gould,sequent) the function is called "random()" and it returns an integer
>from 0 to MAXINT. In Lattice C, a similar function is called "lrand48()"
>and does the same thing but returns from 0 to MAXLONG.  Why the name
>change?

Yes, but if I type "man lrand48" on my big Unix box (lynx), I get a
man page (which is odd, because on lynx, sizeof(short) = sizeof(long)
= sizeof(int) = 64 bits). The catch is that Lynx doesn't run a
BSD-derived Unix. It runs a SysIII/V derived Unix. Note that there are
probably more of those around then 4BSD systems.

In other words, Lattice didn't change the name, they just used a
different Unix than you did.

[Side note: random() & like don't produce -true- random numbers. At
best, they produce a nice long sequece of pseudo-randome numbers. Many
vendor-supplied functions for doing so do so _very_ poorly. If you're
serious about needing a good source of "random" numbers, apply
statistical test to your PRN generator to see if it meets your needs.
If it doesn't right your own. Knuth Vol. 2 is a good place to start
looking.]

>Lattice also didn't like the way some of the string routines
>were named and called some funny names, like "stccpy" for "strcpy".  Before
>anyone flames, yes they do have a #define strcpy stccpy automatically so
>you can still use strcpy.

In this case, sysV doesn't differ from BSD. Don't know why Lattice did
this. Since the "correct" names work, it doesn't matter.

>Speaking of that, I believe someone said
>that Manx has the "index" function, while Lattice uses "stptok" to
>search for a substring.

Wrong on two counts. First, index() doesn't search for substrings, it
searches for characters in a string. strchr() is the Lattice (and
SysIII/V) equivalent. BSD doesn't have a stptok() equivalent. Maybe
something like this is responsible for the "stccpy" names (but I doubt
it, as strcpy is explicitly mentioned as being in the library in K&R).

>Who is standard?  I don't know.

There is no standard. The best that can be done is the dpANS (Draft
Proposed American National Standard). Lattice is working on following
that, and the results can be seen in 3.10. Notice that dpANS trys to
stay with SysIII/V libraries. These are different from the BSD
libraries, which Manx copied. Hopefully, in future releases, Manx will
have routines with the dpANS names.

>But anyways, if your code relies on a lot of these idiosyncratically
>named functions, then it probably won't port.

No, it probably won't compile & run if you copy it. You'll have to
make some changes. But experienced C programmers should be able to
handle all of this with no problem.

Final comment: I'm not trying to start a compiler war. Unfortunately,
Manx doesn't provide near the dpANS compatability that Lattice does. I
consider dpANS to be a good thing, as it will increase the portability
of C programs. Because of this, the above posting may sound like I'm
saying bad things about Manx. I am, in that *I* consider lack of dpANS
compatability to be a bad thing (sort of like lack of flexnames).
However, that is not the only basis for judging compiler, and some
very good people consider it to be totally irrelevant. You've got to
consider your applications, and select a compiler based on that.

	<mike


--
Here's a song about absolutely nothing.			Mike Meyer        
It's not about me, not about anyone else,		ucbvax!mwm        
Not about love, not about being young.			mwm@berkeley.edu  
Not about anything else, either.			mwm@ucbjade.BITNET