[comp.sys.amiga] 32bit = 16bit x 16bit

dca@kesmai.COM (David C. Albrecht) (09/29/87)

I would be interested in some other people's input on this.
One of our latest products where I work is a flight simulator.
We do alot of integer arithmetic.  The original target of the
program was the MAC it has since been ported to the Amiga and
is now being ported to the ST.  Okay, note that these are all
68K machines.  In trying to squeeze more speed out of it on the
Amiga I noticed a good many multiplys were 16x16=32 (which is
supported in hardware on the 68000) while it was currently using
32x32=32 (which is not).  In attempting to get the MULS operation
I made the variables 16bit in size and coded the expression thusly:

((long) (x * y))

It is a bit greasy but it was the only way I could think of to get
the proper result.  On the Amiga using Lattice 3.10 it worked ducky.
Recently we moved the code back to the MAC which is using Counsulair (sp?)
and that also seems to work.  On the ST using Mark Williams we were not
so lucky.  They actually explicitly sign extend the result throwing away
the upper 16bits.  We assumed that they did so because their compiler
was not smart enough to recognize that it already had a long result which
it could just use.  After some communication with them they claimed that
the phrase on pg184 in K&R which says that an expression with two ints
should produce an int (their ints are 16 bits) REQUIRE that they sign
extend or they will fail some of their commercial customers acceptance
suites.  Personally I think they are full of it.

Does anyone know of a commercial test suite that checks to make sure that
y = x * x where x is a 16 bit int and y is long (32 bits)  produces garbage
instead of the proper result?  Seems like just the kind of thing I would
want in my software.  Why have good numbers when I could have garbage?

Seriously, I can understand their compiler being a little simple and not
producing the result I desire because it isn't sharp enough to realise that
the result of a MULS is either 16 bits or 32 bits depending on what you
want.  I find it extremely unlikely that this behavior is required, however.
If someone out there could point out to me the error of my ways and why
an acceptance suite would test this or just relate first hand
experience with a suite that does test this I would be most interested.

David Albrecht

dillon@CORY.BERKELEY.EDU (Matt Dillon) (10/12/87)

	Aztec does this correctly by using MULS/MULU (thank the lords!)... I
depend on it heavily for my graphics work as well... for speed.  Lattice C
isn't quite as smart... you need to put in some casts, but it still does it.
Unfortunetly, most other compilers do not optimize this.   If:

	long z;
	short x,y;

	z = (long)((short)x * (short)y);

	Doesn't work, there probably is no way to do it without using some
assembly.  BTW, the above applies to 32 bit compilers.  16 bit compilers
will usually barf on it since theoretically the result of the multiplication 
is a short if the arguments are short and the compiler would then extend it to 
a long destroying the upper 16 bits.

	You could try the following for 16 bit compilers, but they have to
be *smart*:

	z = (long)((long)x * (long)y);

						-Matt

P.S. that first (long) cast is not strickly required, but some compilers are 
very stupid when it comes to checking the result variable type when applying 
optimization.

rokicki@rocky.STANFORD.EDU (Tomas Rokicki) (10/12/87)

> the phrase on pg184 in K&R which says that an expression with two ints
> should produce an int (their ints are 16 bits) REQUIRE that they sign
> extend or they will fail some of their commercial customers acceptance
> suites.  Personally I think they are full of it.

Actually, no, they are quite correct.  If sizeof(int)==2, and
int x,y ; and long z; and sizeof(long)==4, then

	z = x * y

should generate

	muls	d1,d0
	ext.l	d0

according to K&R; the result *must be* of type int (2 bytes) and therefore
it must be coerced into a long.  The correct way to do this is

	z = x * (long)y ;

which usually generates

	ext.l	d0
	ext.l	d1 ; both operands must be long
	jsr	.muls

but smart compilers (like Manx 3.4) will generate the equivalent

	muls	d1,d0

because the two are exactly idential.  (Similarly, idiotic compilers
will generate, for

char *p, *q ;
if (*p==*q)

	move.b	(a0),d0
	ext.w	d0
	move.b	(a1),d1
	ext.w	d1
	cmp.w	d0,d1

because theoretically, all operations are performed with at least int
accuracy, but smart compilers will generate

	cmp.b	(a0),(a1)

you would be surprised how many generate the former!  Try it.)

> Does anyone know of a commercial test suite that checks to make sure that
> y = x * x where x is a 16 bit int and y is long (32 bits)  produces garbage
> instead of the proper result?  Seems like just the kind of thing I would
> want in my software.  Why have good numbers when I could have garbage?

The rules for C type coercion are well laid down and fairly unambiguous.
Violating them so this one case works is not a good idea.  Specifically,

	int x, y; long z ;

	z = x * y ; /* is not exactly equivalent to */ z = (long)x * (long)y ;
		    /* but */
	z = x * (long)y ; /* is equivalent to */ z = (long)x * (long)y ;

and the lone muls will do the latter, but not the former, if the compiler
is smart enough.  And it doesn't take a much smarter compiler to handle
x * (long)y correctly.

-tom

ark@alice.UUCP (10/13/87)

In article <141@kesmai.COM>, dca@kesmai.UUCP writes:
> Does anyone know of a commercial test suite that checks to make sure that
> y = x * x where x is a 16 bit int and y is long (32 bits)  produces garbage
> instead of the proper result?

Garbage *IS* the proper result.

If x is a 16-bit number, x*x is also a 16-bit number.
The result of overflow is undefined.

If you want the 32-bit product of x and x on a machine with
32-bit longs, the way to write it is

	(long) x * (long) x

or
	x * (long) x

or

	(long) x * x

while is evaluated as

	((long) x) * x

You can then flame at your compiler vendor for not being smart
enough to generate a single instruction for the expression
(in fact, some compilers are smart enough).

rick@oresoft.UUCP (Rick Lahrson) (10/13/87)

In article <141@kesmai.COM> dca@kesmai.COM (David C. Albrecht) writes:
>                      ... In attempting to get the MULS operation
>I made the variables 16bit in size and coded the expression thusly:
>
>((long) (x * y))
>
>It is a bit greasy but it was the only way I could think of to get
>the proper result.  On the Amiga using Lattice 3.10 it worked ducky.
>Recently we moved the code back to the MAC which is using Counsulair (sp?)
>and that also seems to work.  On the ST using Mark Williams we were not
>so lucky.  They actually explicitly sign extend the result throwing away
>the upper 16bits.  We assumed that they did so because their compiler
>was not smart enough to recognize that it already had a long result which
>it could just use.  After some communication with them they claimed that
>the phrase on pg184 in K&R which says that an expression with two ints
>should produce an int (their ints are 16 bits) REQUIRE that they sign
>extend or they will fail some of their commercial customers acceptance
>suites.  Personally I think they are full of it.

I think it's more of an implementation decision.  C tries to fill two
sometimes conflicting niches.  On the one hand, it lets the programmer
get down to the nitty gritty, by making the machine very accessible.
On the other hand, it needs to be as portable as possible.  But porta-
bility for arithmetic requires that you feign ignorance of the actual
capabilities of the machine you're on, and use only capabilities that
all machines/implementations can be expected to have.

For example, if you write:
	a = ((long) (b * c)) / d;
where a, b, c, and d are ints, on a 68K you might expect arithmetically
correct answers for any values of b and c.  But what if an int were 32
bits?  In that case, a long and an int would be the same size, the
multiplication would not be carried to double precision, and some values
of b and c would cause an overflow.  So for portability reasons, the
"common denomimator" among all implementations on all machines seems to
be that the result of a multiplication (1) will contain no fewer bits than
there are in the larger factor (let's hope!); and (2) will contain no
more bits than there are in the larger factor (because many machines/
implementations simply don't provide that capability).

I don't have a C validation suite to look at, and the above definition
of a likely compromise is just my best guess, but I'll bet the compiler
that holds the precision to the size of the operands is the one that
the validation suite will like.

In my copy of K&R, the referenced phrase on p 184 just happens to be ...
The Bottom Line!  8-)

-- 

Rick Lahrson  ...tektronix!oresoft!rick

Disclaimer:  If I ever speak for anyone but me, I'll warn you in advance.

higgin@cbmvax.UUCP (Paul Higginbottom SALES) (10/14/87)

in article <141@kesmai.COM>, dca@kesmai.COM (David C. Albrecht) says:
> Xref: cbmvax comp.lang.c:4799 comp.sys.atari.st:5522 comp.sys.amiga:9125
> 
> I would be interested in some other people's input on this.
> ...I noticed a good many multiplys were 16x16=32 (which is
> supported in hardware on the 68000) while it was currently using
> 32x32=32 (which is not).  In attempting to get the MULS operation
> I made the variables 16bit in size and coded the expression thusly:
> 
> ((long) (x * y))
> 
> It is a bit greasy but it was the only way I could think of to get
> the proper result.  On the Amiga using Lattice 3.10 it worked ducky.
> Recently we moved the code back to the MAC which is using Counsulair (sp?)
> and that also seems to work.  On the ST using Mark Williams we were not
> so lucky.  They actually explicitly sign extend the result throwing away
> the upper 16bits.  We assumed that they did so because their compiler
> was not smart enough to recognize that it already had a long result which
> it could just use.  After some communication with them they claimed that > the phrase on pg184 in K&R which says that an expression with two ints
> should produce an int (their ints are 16 bits) REQUIRE that they sign
> extend or they will fail some of their commercial customers acceptance
> suites.  Personally I think they are full of it.

Personally (and knowing the guys at MWC), I bet they're right.

Second, your expression '((long) (x * y))' should not do as you say because
the cast is performed AFTER the expression is evaluated, so '(x * y)'
is 16bits x 16bits, which is not supposed to be guaranteed to generate 
32 bits, but instead will generate another int (16 bits), the overflow
having probably been lost, or is at least undefined, and THEN the result
is cast to a long, and to make the sign extension work properly, bit 15
will be extended through bits 16-31.
> 
> Does anyone know of a commercial test suite that checks to make sure that
> y = x * x where x is a 16 bit int and y is long (32 bits)  produces garbage
> instead of the proper result?
		 ^^^^^^

This word is important.  I think the result of an OVERFLOWED 16 bit
quantity is undefined.

> David Albrecht

	Paul Higginbottom

mhatter@pnet02.CTS.COM (Patrick E. Hughes) (10/15/87)

In addition to a small letter I sent to the author of the original message
that started this whole mess, I might suggest one thing if you plan on porting
many C programs: Don't Use Ints

Use char, use long, use float, and since they don't change size you're always
set.  Ints, as I've seen, are consistently inconsistent.

UUCP: {hplabs!hp-sdd!crash, ihnp4!scgvaxd!cadovax}!gryphon!pnet02!mhatter
INET: mhatter@pnet02.CTS.COM

crowl@cs.rochester.edu (Lawrence Crowl) (10/16/87)

In article <1912@gryphon.CTS.COM> mhatter@pnet02.CTS.COM
(Patrick E. Hughes) writes:
>I might suggest one thing if you plan on porting many C programs: Don't Use
>Ints.  Use char, use long, use float, and since they don't change size you're
>always set.  Ints, as I've seen, are consistently inconsistent.

NO!  Char, short, and long do change size.  The only thing you can rely on is
that sizeof char <= sizeof short <= sizeof int <= sizeof long.  If you want
portable programs, DO NOT USE BASIC TYPES.  At the top of the program, define a
set of typedefs from program specific types to the basic types.  For example:

     typedef char autos_t ; /* for number of automobiles owned by a person */
                            /* expected range 0 .. 20 */
     typedef int potatoes_t ; /* for number of potatoes eaten by a city */
                            /* expected range 0 .. 80,000,000 */

Because the size of every program type can be changed in exactly one place in
the source, this approach provides two major advantages.  First, it is portable
from one machine to another, and second, it allows the program to adapt to
changing needs or improper design decisions.
-- 
  Lawrence Crowl		716-275-9499	University of Rochester
		      crowl@cs.rochester.edu	Computer Science Department
...!{allegra,decvax,rutgers}!rochester!crowl	Rochester, New York,  14627

dillon@CORY.BERKELEY.EDU (Matt Dillon) (10/17/87)

:>I might suggest one thing if you plan on porting many C programs: Don't Use
:>Ints.  Use char, use long, use float, and since they don't change size you're
:>always set.  Ints, as I've seen, are consistently inconsistent.
:

	This is all moot anyway.  I would like to point out that even if you
*do* use only char's short's and long's you can still get screwed up.  
Something like:

	short a,b;
	long c;

	c = a * b;

	Would yield a different result when run on a 32bit-int vs 16bit-int
compiler.  

	You aren't going to see me writing code like:	c = (long)a * b
with MY 32 bit compiler....  My source would become unreadable if I put in
all that garbage to ensure it was compileable with 'any' C compiler.

:NO!  Char, short, and long do change size.  The only thing you can rely on is
:that sizeof char <= sizeof short <= sizeof int <= sizeof long.  If you want
:portable programs, DO NOT USE BASIC TYPES.  At the top of the program, define a
:set of typedefs from program specific types to the basic types.  For example:

	True... but garbage.  By the same reasons if I made the above 
assumptions when writing C, my source would become unreadable.  Additionaly,
it would take me months rather than weeks to complete large programming
projects.  This is from EXPERIENCE.  There have been several occasions where
I've had to write programs that would compile on both my Amiga and on a
(ich) PC-XT ... and they took about twice as long to write than if for just one
machine.  In fact, other problems turn up that have nothing to do with 
standard C.

	How many of you assume you can fopen() a file and read it byte for
	byte with getc()???  Think again.  But I DO make this assumption 
	whenever I write programs for my Amiga.

	As far as I'm concerned, for any software I will ever write for the
Amiga, integers are 32 bits, shorts are 16 bits, chars are 8 bits.  If I
start writing software for a CRAY in C, I would make different assumptions.
Depending on the machine, my assumptions may be tight (Amiga, Vax), or loose
(Cray).

	And if I ever have to port any of the stuff, tough on me! (or not
so tough as the source would be extremely readable).


					-Matt

andy@cbmvax.UUCP (Andy Finkel) (10/20/87)

In article <3294@sol.ARPA> crowl@cs.rochester.edu (Lawrence Crowl) writes:
>In article <1912@gryphon.CTS.COM> mhatter@pnet02.CTS.COM
>(Patrick E. Hughes) writes:
>>I might suggest one thing if you plan on porting many C programs: Don't Use
>NO!  Char, short, and long do change size.  The only thing you can rely on is
>that sizeof char <= sizeof short <= sizeof int <= sizeof long.  If you want
>portable programs, DO NOT USE BASIC TYPES.  At the top of the program, define a

We at the Banzai Institute always use typedefs :-)

Ours are stored in the include file exec/types.h

To maintain readability, however, the names were a bit a bit boring, ie

LONG, ULONG, WORD, UWORD, BYTE, UBYTE, and VOID.

			andy
-- 
andy finkel		{ihnp4|seismo|allegra}!cbmvax!andy 
Commodore-Amiga, Inc.

"Interfere?  Of course we'll interfere.  Always do what you're best at,
 I always say."

Any expressed opinions are mine; but feel free to share.
I disclaim all responsibilities, all shapes, all sizes, all colors.

jimm@mitsumi.UUCP (Jim Mackraz) (10/20/87)

In article <2545@cbmvax.UUCP> andy@cbmvax.UUCP (Andy Finkel) writes:
)In article <3294@sol.ARPA> crowl@cs.rochester.edu (Lawrence Crowl) writes:
)>In article <1912@gryphon.CTS.COM> mhatter@pnet02.CTS.COM
)>(Patrick E. Hughes) writes:
)>>I might suggest one thing if you plan on porting many C programs: Don't Use
)>NO!  Char, short, and long do change size.  The only thing you can rely on is
)>that sizeof char <= sizeof short <= sizeof int <= sizeof long.  If you want
)>portable programs, DO NOT USE BASIC TYPES.  At the top of the program, define a
)
)We at the Banzai Institute always use typedefs :-)
)Ours are stored in the include file exec/types.h
)To maintain readability, however, the names were a bit a bit boring, ie
)LONG, ULONG, WORD, UWORD, BYTE, UBYTE, and VOID.
)andy finkel		{ihnp4|seismo|allegra}!cbmvax!andy 

Well, one qualification on this business is that sometimes you want
Mr. Compiler to choose its most efficient type.  For example, in Intuition,
there was a large number of cases where SHORT was used in loop counters,
and other places where a small counting number was needed.

There appeared to be explicit sign extension operation frequently applied
to these SHORTs.  When many SHORTS were converted to 'ints', the resulting 
code was significantly smaller (note: significant to people who changed
the name "rawinput" to "ri" because we needed the 6 bytes.  Yea, significant
to people who waited from Jul 31 to Aug 1 for the big build because that
second digit in the date string, multiplied by the number of libraries, ...).

It also broke where a pointer to an 'int' was passed to a program expecting
a pointer to a SHORT.

But *sometimes*, there are *some* reasons for saying 'int' instead of either
LONG or SHORT.

	jimm
-- 
	Jim Mackraz
	Mitsumi Technology, Inc.		408/980-5422
	{amiga,pyramid}!mitsumi!jimm

MAXHAM@RICE.BITNET (Mark Maxham) (10/20/87)

But the 68000 MULS and MULU commands multiply two sixteen bit words
into a 32 bit longword.  Thus they are defined.  Is the question
how C translates from multiplicitive expressions into actual machine
instructions?
     
Mark Maxham      maxham@icsa.rice.edu
     

ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) (10/21/87)

In article <2545@cbmvax.UUCP> andy@cbmvax.UUCP (Andy Finkel) writes:
>We at the Banzai Institute always use typedefs :-)
>To maintain readability, however, the names were a bit a bit boring, ie
>LONG, ULONG, WORD, UWORD, BYTE, UBYTE, and VOID.
>					    ^^^^
	I think your VOID definition is broken.  In the file
exec/interrupts.h is the structure:

struct Interrupt {
	struct Node	is_Node;
	APTR		is_Data;
	VOID		(*is_Code)();
};

	Then, later on, when I try and do this:

foo ()
{
	extern long	bar();

	interrupt.is_Code	= (VOID) bar;
}

	...my compiler throws up.  Something about an invalid use of the
'void' declaration.  I have Manx 3.4b.

	I know, it's probably my fault, so I don't cast it and live with the
warning message....

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
Leo L. Schwab -- The Guy in The Cape	ihnp4!ptsfa -\
 \_ -_		Recumbent Bikes:	      dual ---> !{well,unicom}!ewhac
O----^o	      The Only Way To Fly.	      hplabs / (pronounced "AE-wack")
"Although there are technical differences between the quality of images
created on the Amiga and on our system, we feel that viewers could be misled
to believe otherwise, even with your disclaimers to the contrary."
		-- Ralph J. Guggenheim, Pixar

andy@cbmvax.UUCP (Andy Finkel) (10/21/87)

In article <4261@well.UUCP> ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) writes:
>In article <2545@cbmvax.UUCP> andy@cbmvax.UUCP (Andy Finkel) writes:
>	I think your VOID definition is broken.  In the file
>exec/interrupts.h is the structure:

Interesting...in our exec/types.h file we have a

#define VOID 	void

statement, to put the onus of handling this onto the compiler :-)

typedefing VOID as void caused strangeness with Greenhills C.

Well, something else to look into, I guess.

-- 
andy finkel		{ihnp4|seismo|allegra}!cbmvax!andy 
Commodore-Amiga, Inc.

"Interfere?  Of course we'll interfere.  Always do what you're best at,
 I always say."

Any expressed opinions are mine; but feel free to share.
I disclaim all responsibilities, all shapes, all sizes, all colors.

grr@cbmvax.UUCP (George Robbins) (10/21/87)

In article <4261@well.UUCP> ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) writes:
> In article <2545@cbmvax.UUCP> andy@cbmvax.UUCP (Andy Finkel) writes:
> >We at the Banzai Institute always use typedefs :-)
> >To maintain readability, however, the names were a bit a bit boring, ie
> >LONG, ULONG, WORD, UWORD, BYTE, UBYTE, and VOID.
> >					    ^^^^
> 	I think your VOID definition is broken.  In the file
> exec/interrupts.h is the structure:
> 
> 	Then, later on, when I try and do this:
... 
> foo ()
> {
> 	extern long	bar();
> 	interrupt.is_Code	= (VOID) bar;
> }
> 
> 	...my compiler throws up.  Something about an invalid use of the
> 'void' declaration.  I have Manx 3.4b.

Wait a minute - there are two void concepts: 1) routines that don't return
anything, 2) pointers to things of indeterminate nature.

In you expample, it looks like you are dealing with a long, rather than
a pointer - try (yeech)     = (VOID *) bar;  or why not simply declare
bar() as   VOID *bar();  if this is the only way you are using it?

Me, I'm just a hardware guy this incarnation...

-- 
George Robbins - now working for,	uucp: {ihnp4|rutgers|allegra}!cbmvax!grr
but no way officially representing	arpa: out to lunch...
Commodore, Engineering Department	fone: 215-431-9255 (only by moonlite)

starner@ihlpg.ATT.COM (Guy Starner) (10/23/87)

In article <4261@well.UUCP> ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) writes:
>	... Then, later on, when I try and do this:
>	...
> 	interrupt.is_Code	= (VOID) bar;
> 
> 	...my compiler throws up.

Shouldn't this be:

	interrupt.is_code = (VOID (*)()) bar;
	
That is, cast bar to a pointer to a function returning void.

				Guy Starner
				AT&T Bell Laboratories
				...!ihnp4!ixlpn!starner
-- 

				Guy Starner
				IHP 2F-522, 416-7396
				ixlpn!starner

rico@oscvax.UUCP (10/24/87)

In article <4261@well.UUCP> ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) writes:
>
>	I think your VOID definition is broken.  In the file
>exec/interrupts.h is the structure:
>
>struct Interrupt {
>	struct Node	is_Node;
>	APTR		is_Data;
>	VOID		(*is_Code)();
>};
>
>	Then, later on, when I try and do this:
>
>foo ()
>{
>	extern long	bar();
>
>	interrupt.is_Code	= (VOID) bar;
>}

Sorry Leo, I think you missed it...   it should be

	interrupt.is_Code	= (VOID (*)()) bar;

You want to cast bar into a pointer to a function returning VOID
you *don't* want to cast bar into a VOID.  Casting something to VOID
means "throw it away".  Having thrown it away you can't assign it to
interrupt.is_Code.  The only time you ever (well I can't think of
any other reason right now anyways) want to cast something to VOID
(as opposed to a pointer to VOID or pointer to function returning VOID
 or anything like that) is if you want to discard the return value of
some function.  e.g.

	(VOID)gets(s);    	  /* throw away the return value */
				  /* this keeps lint happy */

		-Rico
-- 
[NSA food: terrorist, cryptography, DES, drugs, CIA, secret, decode]
[CSIS food: supermailbox, tuna, fiberglass coffins, Mirabel, microfiche]
[Cat food: Nine Lives, Cat Chow, Meow Mix, Crave]

mpl@sfsup.UUCP (M.P.Lindner) (10/27/87)

In article <2565@cbmvax.UUCP>, grr@cbmvax.UUCP writes:
> In article <4261@well.UUCP> ewhac@well.UUCP (Leo 'Bols Ewhac' Schwab) writes:
> > In article <2545@cbmvax.UUCP> andy@cbmvax.UUCP (Andy Finkel) writes:
> > >We at the Banzai Institute always use typedefs :-)
> > >To maintain readability, however, the names were a bit a bit boring, ie
> > >LONG, ULONG, WORD, UWORD, BYTE, UBYTE, and VOID.

Here's the final word on several offshoots to the original article I've been
reading.

1.
	> > 	I think your VOID definition is broken.  In the file
	> > exec/interrupts.h is the structure:
	> > 
	> > 	interrupt.is_Code	= (VOID) bar;

What you *should* be doing is
	interrupt.is_Code = (VOID (*)()) bar;

2. as for the person doing
	int	x;

	(long) (x * x)

What *you* should be doing is
	((long) x * x)
since you can't get back the 16 bits lost after you do the
multiply as a 16 bit quantity.

3. as for the people who say "Never use the basic types", I say the following:
	1. use "char" to mean a character or a byte (guaranteed in K&R)
	2. use short for a small integer
	3. use int where the size doesn't matter
	4. use long where you need a long (ie in interfacing to the
	   OS, etc.)
	5. use pointers with care
	6. use void where you mean void (either the compiler handles it
	   or it doesn't - if it does, great, if it doesn't, try "cc -Dvoid=int"
	   but don't go changint the input language because you have a bad
	   compiler.
	7. NEVER NEVER NEVER! use LONG, ULONG, VOID, etc.
	   if you're using ULONG because you want an unsigned 32 bit integer
	   try using
		typedef unsigned long	uint32;
		typedef long	int32;
	  so someone can try to figure out what bizzare thing you were trying
	  to do.

Mike Lindner
attunix!mpl

crowl@cs.rochester.edu (Lawrence Crowl) (10/27/87)

In article <2262@sfsup.UUCP> mpl@sfsup.UUCP (M.P.Lindner) writes:
>3. as for the people who say "Never use the basic types", I say the following:
>	1. use "char" to mean a character or a byte (guaranteed in K&R)

Use char to mean a character.  Use "typedef char applicationtype" when the best
implementation for the intended use happens to be a char on your machine.  My
six bit char may not give the range you assumed because of your chars are
twelve bits.

>	2. use short for a small integer

Use "typedef short applicationtype" when the best implementation for the
intended use happens to be a short on your machine.  My short may be longer
than your short.  This way I only have to change the implementation in one
place.

>	3. use int where the size doesn't matter

Use "typedef int applicationtype" when the implementation for the intended use
does not matter significantly.  Let's hope my ints are at least as large as
you assume.

>	4. use long where you need a long (ie in interfacing to the OS, etc.)

Use a crowbar where you need a crowbar?  Use "typedef long systemtype" when the
implementation for the system type is a long.  When porting, changing the
types passed to system routines in one place can reduce hassle considerably.

>	5. use pointers with care

Amen.

>	6. use void where you mean void (either the compiler handles it or
>	   it doesn't - if it does, great, if it doesn't, try "cc -Dvoid=int"
>	   but don't go changing the input language because you have a bad
>	   compiler.

Agreed.

>	7. NEVER NEVER NEVER! use LONG, ULONG, VOID, etc.
>	   if you're using ULONG because you want an unsigned 32 bit integer
>	   try using
>		typedef unsigned long	uint32;
>		typedef long	int32;
>	  so someone can try to figure out what bizzare thing you were trying
>	  to do.

Use "typedef BASIC_TYPE APPLICATION_TYPE /* required range is a..b */".  This
documents the program's needs and allows people porting the program to identify
exactly what changes need to be made.

-- 
  Lawrence Crowl		716-275-9499	University of Rochester
		      crowl@cs.rochester.edu	Computer Science Department
...!{allegra,decvax,rutgers}!rochester!crowl	Rochester, New York,  14627