[comp.sys.amiga] Amiga programmer's hint $14

cunniff@hpfclq.HP.COM (Ross Cunniff) (02/09/88)

For those of you who are using the Manx compiler (and perhaps for
those of you using 16-bit ints with the Lattice compiler), here's
a tip to help you avoid the Guru on machines with more that 512K.
This really happened to a friend of mine (we spent an entire WEEKEND
sorting this out; I would've seen it sooner, but Lattice promotes
bad programming practices :-< ).

	Q. What's wrong with this program?

	   #include <intuition/intuition.h>
	   struct IntuitionBase *IntuitionBase;
	   main()
	   {
	       IntuitionBase = (struct IntuitionBase *)
				OpenLibrary( "intuition.library", 33L );
	       JRandomIntuitionCall( .... );
	   }

	A. OpenLibrary is not declared explicitly as returning a
	   pointer.  This means that the compiler implicitly assumes
	   that it is returning an int.  On compilers which use
	   32-bit ints, this is no problem.  If you are using 16-bit
	   ints, this will Guru on a machine with $C000000 memory,
	   but *NOT* on a stock 512k Amiga.  Why?  Well, since
	   OpenLibrary returns an int (as far as the compiler knows),
	   the compiler just uses the *lower 16 bits* of the return value
	   when it stuffs it into IntuitionBase.  This is just ducky
	   on a 512K machine.  It's not so nice on a machine with more.
	   The solution?

	   #include <intuition/intuition.h>
	   struct IntuitionBase *IntuitionBase;
	   main()
	   {
	       struct Library
		   *OpenLibrary();	/* NOTE THE ADDITION OF THIS DECL! */

	       IntuitionBase = (struct IntuitionBase *)
				OpenLibrary( "intuition.library", 33L );
	       JRandomIntuitionCall( .... );
	   }

	   (I believe that the Manx compiler has a header file that
	   defines the return value of calls such as OpenLibrary; I
	   think it may be called <functions.h>).

				Ross Cunniff
				Hewlett-Packard System Sofware Operation
				...{ucbvax,hplabs}!hpda!cunniff
				cunniff%hplabs@hpda.ARPA

toebes@sas.UUCP (John Toebes) (02/19/88)

In article <4230019@hpfclq.HP.COM>, cunniff@hpfclq.HP.COM (Ross Cunniff) writes:
> For those of you who are using the Manx compiler (and perhaps for
> those of you using 16-bit ints with the Lattice compiler), here's
> a tip to help you avoid the Guru on machines with more that 512K.
> This really happened to a friend of mine (we spent an entire WEEKEND
> sorting this out; I would've seen it sooner, but Lattice promotes
> bad programming practices :-< ).
> 	Q. What's wrong with this program?
> 	   #include <intuition/intuition.h>
> 	   struct IntuitionBase *IntuitionBase;
> 	   main()
> 	   {
> 	       IntuitionBase = (struct IntuitionBase *)
> 				OpenLibrary( "intuition.library", 33L );
> 	       JRandomIntuitionCall( .... );
> 	   }
> 	A. OpenLibrary is not declared explicitly as returning a
> 	   pointer.
Under 4.0 (which supports short integers) the compiler will complain with
error 101 whenever you do this.  I have seen too many people get bit by
this on the PC to let it happen on the Amiga with Lattice.  The basic
rule is that if you ever convert a 16 bit entity to a pointer *REGARDLESS
OF ANY CAST* it will issue the error message.  This will catch almost
all of the errors of this type (only one it can't is if you do it through
indirect pointers in a called subroutine or in assembler - but then again
it isn't apparent from the source code anyway).

There is also a compiler switch -cf that will have the compiler scream
if you ever call anything for which there is no prototype.  Personnaly,
I always compile with the switch and demand that the compile proceed
without warnings, but I like the compiler to find my errors instead of having
to wait for the GURU to find them :-)

/*---------------------All standard Disclaimers apply---------------------*/
/*----Working for but not officially representing SAS or Lattice Inc.-----*/
/*----John A. Toebes, VIII             usenet:...!mcnc!rti!sas!toebes-----*/
/*------------------------------------------------------------------------*/

peter@nuchat.UUCP (Peter da Silva) (02/22/88)

In fact Manx will compain if you convert any scalar to a pointer, no matter
what size it is. I suspect that this is only a problem for people who
use Manx but turn off the warnings. They deserve whatever they get.

The program listed, however, should have checked that IntuitionBase was
properly opened.
-- 
-- a clone of Peter (have you hugged your wolf today) da Silva  `-_-'
-- normally  ...!hoptoad!academ!uhnix1!sugar!peter                U
-- Disclaimer: These aren't mere opinions... these are *values*.

fnf@mcdsun.UUCP (Fred Fish) (02/23/88)

In article <340@sas.UUCP> toebes@sas.UUCP (John Toebes) writes:
>Under 4.0 (which supports short integers) the compiler will complain with
>error 101 whenever you do this.  I have seen too many people get bit by
>this on the PC to let it happen on the Amiga with Lattice.  The basic
>rule is that if you ever convert a 16 bit entity to a pointer *REGARDLESS
>OF ANY CAST* it will issue the error message.  This will catch almost

This really should be discussed on comp.lang.c, but I'd like to note that
traditionally, a cast has been used to tell the compiler that the
programmer really DOES understand what he is asking for, and what the
expected results will be.  In the example program given, the programmer
obviously didn't understand that casting the result of the function call
to a pointer, when the result was a short, didn't automatically magically
turn the function into one that returned a 32 bit value rather than 16.
Breaking the compiler to catch broken programs does not seem like the
optimal solution.  I could support generating a warning message here,
but NEVER an error, and only generating a warning when the compiler
was specifically requested to flag such questionable constructs.

-Fred
-- 
# Fred Fish    hao!noao!mcdsun!fnf    (602) 438-3614
# Motorola Computer Division, 2900 S. Diablo Way, Tempe, Az 85282  USA

fgd3@jc3b21.UUCP (Fabbian G. Dufoe) (02/29/88)

In article <707@mcdsun.UUCP>, fnf@mcdsun.UUCP writes:
> In article <340@sas.UUCP> toebes@sas.UUCP (John Toebes) writes:
> >Under 4.0 (which supports short integers) the compiler will complain with
> >error 101 whenever you ... convert a 16 bit entity to a pointer *REGARDLESS
> >OF ANY CAST* it will issue the error message.  This will catch almost
> 
> This really should be discussed on comp.lang.c, but I'd like to note that
> traditionally, a cast has been used to tell the compiler that the
> programmer really DOES understand what he is asking for, and what the
> expected results will be.  ... I could support generating a warning 
> message here, but NEVER an error ...

Generally I would agree that a cast is the programmer's way of telling the
compiler that he really understands what he is doing and wants to do it.
However, pointers are a special case, I think.  Trying to convert a 16 bit
value to a pointer won't work if the memory pointed to has an address
higher than FFFF.  Since C doesn't let you control the actual memory
addresses to which you might want to point you have no guarantee unless the
machines doesn't have an address space larger than 64K.  So it seems
reasonable to me for the compiler to treat that as an error.  Even if you
write for a 64K machine (shudder) the goal of portability demands that you
not cast shorts to pointers because it will break on any larger machines.
Is there any way you can cast shorts to pointers in a way that won't break
if you have enough memory?


--Fabbian Dufoe
  350 Ling-A-Mor Terrace South
  St. Petersburg, Florida  33705
  813-823-2350

UUCP: ...gatech!codas!usfvax2!jc3b21!fgd3 

kurt@tc.fluke.COM (Kurt Guntheroth) (03/04/88)

I used to think a cast was a way to unlock the type system in C too, but it
turns out not to be.  A cast is a type conversion operator and a cast can
generate code.  For instance, 

    int foo;
    float bar;

    bar = (float) foo;

should generate code to convert foo to a float.  Furthermore, the result of
a cast is an rvalue.  That is why you can't always use casts on the left
side of an assignment.  Now, some compilers, like the BSD vax compiler
permit this, but others, like the Sun compiler, do not.  (Talking to Sun
service is how I learned about casts.)  There is a relevant chapter and
verse in K&R too.  Anyone remember where it is?

Oh, by the way, this discussion has also been on comp.lang.c.

dillon@CORY.BERKELEY.EDU (Matt Dillon) (03/04/88)

>generate code.  For instance, 
>    int foo;
>    float bar;
>    bar = (float) foo;
>should generate code to convert foo to a float.  Furthermore, the result of
>a cast is an rvalue.  That is why you can't always use casts on the left
>side of an assignment.  Now, some compilers, like the BSD vax compiler

	On the left side of an assignment?  Yow! That isn't C.  Still, if
you want to cheat you can get around the automatic type conversion:

	int foo;
	float bar;
	bar = *(float *)&foo;	/*sizeof(float) had better equal sizeof(int)*/
				/*for this to work	*/

	Believe it or not, I have seen people do this!  Actually, this sort
of thing is useful in certain cases.  But I digress.  As far as C goes,
this is the deal with casts:

	(anycast)variable = variable;		NOT LEGAL
	variable = &(anycast)variable;		NOT LEGAL

	variable = (somecasts)&variable;	LEGAL

	char c = *(char *)&bar;			LEGAL. (USEFUL?)


					-Matt

scott@applix.UUCP (Scott Evernden) (03/06/88)

In article <8803032106.AA06910@cory.Berkeley.EDU> dillon@CORY.BERKELEY.EDU (Matt Dillon) writes:
>
> <CASTS> On the left side of an assignment?  Yow! That isn't C.
>
I have done this kind of thing now and then, and I believe that it's
legal C.  I have not yet discovered a compiler that complains about this:

struct point {
    int x, y;
} p1, p2;

struct rect {
    int x1, y1, x2, y2;
} r;

alpha()
{
    * (struct point *) &r.x1 = p1;
    * (struct point *) &r.x2 = p2;
}

-scott

dillon@CORY.BERKELEY.EDU (Matt Dillon) (03/07/88)

:In article <8803032106.AA06910@cory.Berkeley.EDU> dillon@CORY.BERKELEY.EDU (Matt Dillon) writes:
:>
:> <CASTS> On the left side of an assignment?  Yow! That isn't C.
:I have done this kind of thing now and then, and I believe that it's
:legal C.  I have not yet discovered a compiler that complains about this:
:    * (struct point *) &r.x1 = p1;
:    * (struct point *) &r.x2 = p2;
:}
:
:-scott

	Sure, that works fine.  What I meant was assigning something TO
a cast, ala:	(long)x = 43;  is what is illegal.  One thing to remember
is that structure assignment is somewhat new in C, and thus not all compilers
have been upgraded to it yet.

						-Matt

shimoda@rmi.UUCP (Markus Schmidt) (03/07/88)

In article <8803032106.AA06910@cory.Berkeley.EDU> dillon@CORY.BERKELEY.EDU (Matt Dillon) writes:
: 
: 	(anycast)variable = variable;		NOT LEGAL
: 	variable = &(anycast)variable;		NOT LEGAL
: 
: 	variable = (somecasts)&variable;	LEGAL
: 
: 	char c = *(char *)&bar;			LEGAL. (USEFUL?)
: 
Yeah, useful in some cases, but can be also dangerous if you
hit odd addresses for ints and longs.
So  a       char foo[4]= {\{1, 2, 3, 4};
           
            b= *(int *)foo+1;

may give you (and gave me) the guru!

Cu 
Markus
(shimoda@rmi.uucp)

dillon@CORY.BERKELEY.EDU (Matt Dillon) (03/09/88)

>: 	char c = *(char *)&bar;			LEGAL. (USEFUL?)
>: 
>Yeah, useful in some cases, but can be also dangerous if you
>hit odd addresses for ints and longs.
>So  a       char foo[4]= {\{1, 2, 3, 4};
>           
>            b= *(int *)foo+1;

	Yah, that's why I used *(char *) in my example.  The proper
way to cast to other types with possible alignment problems is to use
a union, but you still have to be careful when overlaying structures
on buffers (that caught me a couple of times!).

				-Matt