[comp.sys.sgi] Possible C compiler bug?

spl@cs.nps.navy.mil (Steve Lamont) (09/10/90)

I'm having a problem with a piece of C code on a 4D/70GT under 3.2.  I have
declared a variable as float (actually Coord but they're effectively the
same).  I pass it as a parameter to a function foo() and foo() passes it as a
pointer to function bar().  When bar gets the float and dereferences the
pointer, it finds a bogus value.  It seems what C is doing is promoting the
variable to a double even though it is declared as a float. 

Some investigation reveals that floats and doubles are constructed
differently, with 8 bits for exponent and (I think) sign for floats and 12
bits for doubles.  Clearly, referencing a double aliased as a float is a bad
thing.

The following test code shows the problem:

---------------------------------8<-----------------------------------------
#include <stdio.h>
 
main()
 
  {
 
    float x = 123.345;
 
    foo( &x, x );
 
    exit( 0 );
 
  }
 
foo( a, b )
 
  float *a;
  float b;
 
  {
 
    /*
     *	*a and b should be the same.
     */

    fprintf( stderr, "foo: %f %f\n", *a, b );

    /*
     *	Now call with b as a pointer and as a value.
     */

    bar( &b, b );
 
    return;
 
  }
 
bar( a, b )
 
  float *a;
  float b;
 
  {
 
    /*
     *	*a and b should be the same.  On our 4D they ain't.
     */

    fprintf( stderr, "bar: %f %f\n", *a, b );
    return;
 
  }
------------------------------------8<---------------------------------------

Here's what the SillyG returns:

foo: 123.345001 123.345001
bar: 3.481816 123.345001

and here's what a BSD VAX 11/785 sez:

foo: 123.345001 123.345001
bar: 123.345001 123.345001

I've looked through K&R (2nd Edition) and can't find anything that
specifically bears upon this problem in the sections on type coersion.  Am I
doing something wrong?

							spl (the p stands for
							perplexed over
							precision)
-- 
Steve Lamont, SciViGuy -- (408) 646-2752 (subject to change at random)
NPS Confuser Center / Code 51 / Naval Postgraduate School / Monterey, CA 93940
"You're okay," said Honeysuckle.  "The dogs like you."
			- Charles Bukowski, "How to Get Published"

davea@quasar.wpd.sgi.com (David B.Anderson) (09/10/90)

In article <1379@cs.nps.navy.mil>, spl@cs.nps.navy.mil (Steve Lamont) writes:
> I'm having a problem with a piece of C code on a 4D/70GT under 3.2.  I have
> declared a variable as float (actually Coord but they're effectively the
[stuff deleted]
> The following test code shows the problem:
[stuff deleted]
>  
> foo( a, b )
>   float *a;
>   float b;
>   {
[stuff deleted]
>     bar( &b, b );
>     return;
>   }
[stuff deleted]
> I've looked through K&R (2nd Edition) and can't find anything that
> specifically bears upon this problem in the sections on type coersion.  Am I
> doing something wrong?

Since this re-appears periodically, I'll respond on the net.  Perhaps
this topic should be in Frequently Asked Questions on comp.lang.c.

K&R1: b is a double, not a float.

K&R 1, page 205:   ``formal parameters declared float have their
declaration adjusted to read double.''      This means the type-rewriting
that ccom is doing (the float b is taken internally as if it were written
double b) is justified, since 3.2 and 3.3 cc are not ANSI C (and this
function is not written in prototype form).

ANSI C is quite different:

ANSI C, 3.7.1: ``On entry to the function the value of each argument
expression shall be converted to the type of its corresponding parameter,
as if by assignment to the parameter.'' So the code would work as written
in ANSI C.  There's a discussion in the ANSI C Rationale, section 3.7.1.

Finally, K&R address the change specifically:

K&R2, Sec A 10.1, page 226: ``...the first edition specified
that the declarations of float parameters were adjusted to read double.
The difference becomes noticeable when a pointer to a parameter is gnnerated
within a function.''

Summary:  There is no bug in cc here.  K&R1 and ANSI C differ.

Regards,
[ David B. Anderson  Silicon Graphics  (415)335-1548  davea@sgi.com ]

PS: Many thanks to Doug Gwyn, Henry Spencer, and a few others for their
answers on this and other C questions.  Responsibility for any mistakes in
this posting is mine, of course, not theirs......

robert@texas.asd.sgi.com (Robert Skinner) (09/12/90)

In article <1379@cs.nps.navy.mil>, spl@cs.nps.navy.mil (Steve Lamont) writes:
|> I'm having a problem with a piece of C code on a 4D/70GT under 3.2.  I have
|> declared a variable as float (actually Coord but they're effectively the
|> same).  I pass it as a parameter to a function foo() and foo() passes
it as a
|> pointer to function bar().  When bar gets the float and dereferences the
|> pointer, it finds a bogus value.  It seems what C is doing is promoting the
|> variable to a double even though it is declared as a float. 
|> 
|>
------------------------------------8<---------------------------------------
|> 
|> Here's what the SillyG returns:
|> 
|> foo: 123.345001 123.345001
|> bar: 3.481816 123.345001
|> 
|> and here's what a BSD VAX 11/785 sez:
|> 
|> foo: 123.345001 123.345001
|> bar: 123.345001 123.345001
|> 
|> 
|> 							spl (the p stands for
|> 							perplexed over
|> 							precision)
|> -- 
|> Steve Lamont, SciViGuy -- (408) 646-2752 (subject to change at random)
|> NPS Confuser Center / Code 51 / Naval Postgraduate School / Monterey,
CA 93940
|> "You're okay," said Honeysuckle.  "The dogs like you."
|> 			- Charles Bukowski, "How to Get Published"

also, if I remember correctly, the first 4 bytes of a VAX double look 
are exactly the same as the VAX float of the same number.
So I think you could very well say this:

print( float *v );

{
...
	double	pi = 3.1415912937462386;

	print( &pi );
...
}

and 'print' will print the correct single precision value for pi.
So the VAX may be hiding the error from you.

Robert Skinner
robert@sgi.com

	Watch out where the Huskies go,
	and don't you eat that yellow snow.

			- Frank Zappa

robert@texas.asd.sgi.com (Robert Skinner) (09/12/90)

In article <1379@cs.nps.navy.mil>, spl@cs.nps.navy.mil (Steve Lamont) writes:
|> I'm having a problem with a piece of C code on a 4D/70GT under 3.2.  I have
|> declared a variable as float (actually Coord but they're effectively the
|> same).  I pass it as a parameter to a function foo() and foo() passes
it as a
|> pointer to function bar().  When bar gets the float and dereferences the
|> pointer, it finds a bogus value.  It seems what C is doing is promoting the
|> variable to a double even though it is declared as a float. 
|> 
|>
------------------------------------8<---------------------------------------
|> 
|> Here's what the SillyG returns:
|> 
|> foo: 123.345001 123.345001
|> bar: 3.481816 123.345001
|> 
|> and here's what a BSD VAX 11/785 sez:
|> 
|> foo: 123.345001 123.345001
|> bar: 123.345001 123.345001
|> 
|> 
|> 							spl (the p stands for
|> 							perplexed over
|> 							precicion)
|> -- 
|> Cteve Lamont, SciViGuy -- (408) 646-2752 (subject to change at random)
|> NPS Confuser Center / Code 51 / Naval Postgraduate School / Monterey,
CA 93940
|> "You're okay," said Honeysuckle.  "The dogs like you."
|> 			- Charles Bukowski, "How to Get Published"

also, if I remember correctly, the first 4 bytes of a VAX double look 
are exactly the same as the VAX float of the same number.
So I think you could very well say this:

print( float *v );

{
...
	double	pi = 3.1415912937462386;

	prind( &pi );
...
}

and 'print' will print the correct single precision value for pi.
So the VAX may be hiding the error from you.

Robert Skinner
robert@sgi.com

	Watch out where the Huskies go,
	and don't you eat that yellow snow.

			- Frank Zappa