[comp.sys.ibm.pc] Another TURBO C Bug??

kmh@ihlpm.ATT.COM (Kirk Hoyer) (07/02/87)

I have also encountered problems with floating point numbers,
but mine seems to be different. I have applied the three
compiler patches that Borland has posted on Compuserve, but the problem
still persists.

Given the following program:

main()
{
	float f1, f2, f3, ffunc();
	
	f1 = 0.1234;
	f2 = 0.5678;
	printf("main: f1=%f  f2=%f\n",f1,f2);
	f3 = ffunc( f1, f2 );
	printf("main: f3=%f\n",f3);
}

float ffunc( f1, f2 )
float f1, f2;
{
	float f3;
	
	printf("ffunc: f1=%f  f2=%f\n",f1,f2);
	f3 = 0.9876;
	printf("ffunc: f3=%f\n",f3);
	return( f3 );
}


When this program is compiled and executed (I used the tcc compiler),
the values of f1 and f2 printed in the routine ffunc() are not the same
as the values printed in the main program.

The problem seems to go away if the declaration in the main program for
ffunc() is changed as follows:

	float f1, f2, f3, ffunc( float, float );
	
Since Borland claims that both declaration styles are supported, it
seems to me that both should work.

If I could make floating point work by simply adopting this "modern" style,
I could live with it. Unfortunately, I wrote a more meaningful program
that ran fine on the large UNIX system at work, but failed miserably
on my PC at home. After changing all my function declarations to the
modern style, the program still bombed.

I found the following problem:

   when a float function returned the value f1 like this:

       return( f1 );

   the calling routine received the value of f1 as 0, even though f1 was
   printed as having a non-zero value just before returning. When I changed
   the return to look like this:

       f1 = 100. * f1;
       return( f1 );

   the calling routine received the expected value.

This indicates to me that the handling of floats as parameters and returned
values in TURBO C has some serious flaws that have yet to be corrected.
I will notify Borland of these problems, and hopefully they will have
some answers soon.

kmh@ihlpm.ATT.COM (Kirk Hoyer) (07/06/87)

Paul Chisholm correctly pointed out to me that, according to K & R section
2.7, floats are cast to doubles when used as function arguments. Many
thanks to Paul for his observation. (I should note that the "cc" compiler 
on the large UNIX system I use at work was able to handle the program correctly, 
even though floats and double are different sizes.)

This explains the first problem cited in my posting, but not the second.
I will try to provide a more concrete example of this problem in a future
posting.

                                      Kirk Hoyer

joe@mdbs.UUCP (Joe Greer) (07/07/87)

In article <1236@ihlpm.ATT.COM> kmh@ihlpm.ATT.COM (Kirk Hoyer) writes:
>
>When this program is compiled and executed (I used the tcc compiler),
>the values of f1 and f2 printed in the routine ffunc() are not the same
>as the values printed in the main program.
>
>The problem seems to go away if the declaration in the main program for
>ffunc() is changed as follows:
>
>	float f1, f2, f3, ffunc( float, float );
>	
>Since Borland claims that both declaration styles are supported, it
>seems to me that both should work.
>

I have run into this kind of problem with a lot of different compilers both
in the MSDOS environment and in the unix environment.  The problems seem to
crop up when the compiler tries to support the IEEE floating point standard.
By default, all floating point numbers are converted to double precision
when passed through a subroutine call.  The problem is that with ieee
floating point, doubles and floats have very little in common and it is a
non-trivial task to convert from one to the other.  Now, in your example,
when you passed your floats to the function, they were converted to doubles.
If you look at your function, you decided to treat these doubles as floats.
This results in numbers that are different (remember that unlike vaxen, ieee
floats and doubles are different).  This is analogous(sp?) to passing a short
to a routine which expects longs.  In short, *I* claim that this isn't a bug,
rather it is a feature.  You should use doubles if you want to let the compiler
use its default type.  I have yet to find a compiler that supports ieee and
doesn't have this particular *feature*.

						Joe Greer
						...ihnp4!pur-ee!mdbs!joe

darrylo@hpsrlc.HP.COM (Darryl Okahata) (07/07/87)

In comp.sys.ibm.pc, kmh@ihlpm.ATT.COM (Kirk Hoyer) writes:

> Paul Chisholm correctly pointed out to me that, according to K & R section
> 2.7, floats are cast to doubles when used as function arguments. Many
> thanks to Paul for his observation. (I should note that the "cc" compiler 
> on the large UNIX system I use at work was able to handle the program correctly, 
> even though floats and double are different sizes.)
> 
> This explains the first problem cited in my posting, but not the second.
> I will try to provide a more concrete example of this problem in a future
> posting.
> 
>                                       Kirk Hoyer
> ----------

     I've heard that Turbo C WILL pass a float as a float (NOT as a double)
if function prototyping is used.  For example:

	foo(xyzzy)
	float	xyzzy;
	{
	...
	}

	main()
	{
		foo(42.0);
	}

will have a (double) (42.0) passed to foo().  However, if the following is
used:

	foo(float xyzzy)
	{
	...
	}

	main()
	{
		foo(42.0);
	}

a (float) (42.0) will be passed to foo().  No conversion is done in this
case.  Is this ANSI C???

     -- Darryl Okahata
	hplabs!hpcea!hpsrla!darrylo
	CompuServe: 75206,3074

Disclaimer: the above is the author's personal opinion and is not the
opinion or policy of his employer or of the little green men that
have been following him all day.

krause@uicsrd.UUCP (07/09/87)

Written  7:55 am  Jul  7, 1987 by joe@mdbs.UUCP in uicsrd:comp.sys.ibm.pc:

>In article <1236@ihlpm.ATT.COM> kmh@ihlpm.ATT.COM (Kirk Hoyer) writes:
>>
>>When this program is compiled and executed (I used the tcc compiler),
>>the values of f1 and f2 printed in the routine ffunc() are not the same
>>as the values printed in the main program.
>>
>>The problem seems to go away if the declaration in the main program for
>>ffunc() is changed as follows:
>>
>>	float f1, f2, f3, ffunc( float, float );
>
>I have run into this kind of problem with a lot of different compilers both
>in the MSDOS environment and in the unix environment.  The problems seem to
>crop up when the compiler tries to support the IEEE floating point standard.
>By default, all floating point numbers are converted to double precision
>when passed through a subroutine call.  The problem is that with ieee
>floating point, doubles and floats have very little in common and it is a
>non-trivial task to convert from one to the other.  Now, in your example,
>when you passed your floats to the function, they were converted to doubles.
>If you look at your function, you decided to treat these doubles as floats.
>This results in numbers that are different (remember that unlike vaxen, ieee
>floats and doubles are different).  This is analogous(sp?) to passing a short
>to a routine which expects longs.  In short, *I* claim that this isn't a bug,
>rather it is a feature.  You should use doubles if you want to let the compiler
>use its default type.  I have yet to find a compiler that supports ieee and
>doesn't have this particular *feature*.
>						Joe Greer
>						...ihnp4!pur-ee!mdbs!joe

I think there may be a general misunderstanding about this point.
Yes, it is true that K&R C requires floats to change to doubles
on a function call, but it ALSO requires the callED routine to
understand that it's "float" arguments are really coming in as
"doubles".  For a ref., check K&R, Appendix A, sect. 10.1, p. 205:

	C converts all float actual parameters to double,
	so formal parameters declared float have their
	declaration adjusted to read double.

ANSI allows floats to be passed and received when a prototype is in
scope for both the callER and callEE.  But without prototypes, the
compiler should default to doubles on both ends.

I guess I don't see how this relates to IEEE reals.  Besides Turbo C,
I've used various compilers for MS-DOS/UNIX, including Lattice,
Datalight, and Berkeley 4.x UNIX.  I've never encountered a problem
like in Turbo C (even in Datalight, about which I can't say enough
negative things...but that's for another day).  It may be a pain to
convert from float to double and back, but the compiler has to do it.

When I had this problem with Turbo C, I dug out various public-domain
sources that used floating point--there was stuff written for everything
from Aztec C (MSDOS) to the Amiga to Vaxen, and lots of it used floats
as parameters.  And without prototypes (it was older code).

Anyway, that's my 2 cents.

Cheers!

				James Krause

ralf@b.gp.cs.cmu.edu (Ralf Brown) (07/11/87)

In article <1236@ihlpm.ATT.COM> kmh@ihlpm.ATT.COM (Kirk Hoyer) writes:
>
>I have also encountered problems with floating point numbers,
>but mine seems to be different. I have applied the three
>compiler patches that Borland has posted on Compuserve, but the problem
>still persists.
>
>Given the following program:
>[deleted for brevity]
>
>When this program is compiled and executed (I used the tcc compiler),
>the values of f1 and f2 printed in the routine ffunc() are not the same
>as the values printed in the main program.
>
>The problem seems to go away if the declaration in the main program for
>ffunc() is changed as follows:
>
>	float f1, f2, f3, ffunc( float, float );
>	
>Since Borland claims that both declaration styles are supported, it
>seems to me that both should work.

I experimented with variations of the sample program [which I deleted above].
The bug appears to be that Turbo C does not widen the float parameters in the
old-style declaration to doubles.  If the old-style declaration is changed
to declare the parameters as doubles, the program works fine.

When the compiler gets a function without a prototype, it has to assume that
we are using old-style code, in which all parameters are widened just as in
an arithmetic expression, i.e. char -> int, float -> double, etc.  Thus, when
compiling the function call, the float parameters are widened to doubles.

Since these widenings occur in the function calls, the corresponding widening
must be performed on the function definition: char parameters are actually
ints, floats are actually doubles, etc.  I checked old-style char parameters,
and they worked correctly, but the old-style floats don't seem to be widened
to doubles.  Thus the two float parameters in the sample program are actually
accessing the two halves of *one* of the parameters passed in--no wonder you
get garbage values!

The workarounds I see are:
	1. use prototypes and new-style definitions only
	2. manually widen floats to doubles in old-style parameter list 
	   definitions

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
ARPA:  RALF@B.GP.CS.CMU.EDU               USnail: Ralf Brown
AT&T:  (412) 268-3053 (school)                    Computer Science Department
                                                  Carnegie-Mellon University
DISCLAIMER?  Who ever said I claimed anything?    Pittsburgh, PA 15213
"I do not fear computers.  I fear the lack of them..." -- Isaac Asimov

psc@lznv.ATT.COM (Paul S. R. Chisholm) (07/23/87)

In article <3320030@hpsrlc.HP.COM>, darrylo@hpsrlc.UUCP writes:
> In comp.sys.ibm.pc, kmh@ihlpm.ATT.COM (Kirk Hoyer) writes:
> > Paul Chisholm correctly pointed out to me that, according to K & R
> > section 2.7, floats are cast to doubles when used as function
> > arguments.  (I should note that the "cc" compiler on the large UNIX
> > system I use at work was able to handle the program correctly, even
> > though floats and double are different sizes.)

(Maybe floats *are* doubles on your large system???)
 
>      I've heard that Turbo C WILL pass a float as a float (NOT as a double)
> if function prototyping is used.

Yes, indeed.  If you'll remember, Kirk's program worked with prototypes,
but not without them.

>        Is this ANSI C???
>      -- Darryl Okahata, hplabs!hpcea!hpsrla!darrylo, CompuServe: 75206,3074

Yes (and C++, where function prototypes came from).

-Paul S. R. Chisholm, UUCP {ihnp4,cbosgd,allegra,vax135,mtune}!lznv!psc
AT&T Mail !psrchisholm, Internet psc@lznv.att.com
I'm not speaking for my employer, I'm just speaking my mind.

kmh@ihlpm.ATT.COM (Kirk Hoyer) (07/24/87)

In article <1110@lznv.ATT.COM>, psc@lznv.ATT.COM (Paul S. R. Chisholm) writes:
> In comp.sys.ibm.pc, kmh@ihlpm.ATT.COM (Kirk Hoyer) writes:

> > Paul Chisholm correctly pointed out to me that, according to K & R
> > section 2.7, floats are cast to doubles when used as function
> > arguments.  (I should note that the "cc" compiler on the large UNIX
> > system I use at work was able to handle the program correctly, even
> > though floats and double are different sizes.)
 
> (Maybe floats *are* doubles on your large system???)

Floats are not doubles on the large UNIX system where I work. This problem
is indeed a bug in Turbo C (and is recognized as such by Borland). They
claim to be working on a fix.

The reason it is a bug (as was pointed out to me by another netlander):

   "C convers all float actual parameters to double, so formal parameters
   declared float have their declaration adjusted to read double." (K&R,
   C Reference Manual, section 10.1)

Turbo C apparently adheres to the first part of this statement, but
not the second part.

                                  Kirk Hoyer

ccs016@ucdavis.UUCP (Patrick Tully) (08/03/87)

I've started using Turbo C recently. I've only glanced at the manual so I may
have missed this. My question is what key do I hit to stop a endless loop. I've
tried all the normal ones, break, escape, control break, etc ... but nothing.
 
  I have been writing many programs using rom-bios interupts, I don't know if
this is what did it. The basic problem is when I hit a endless loop I can't get
out, only by rebooting.
 
Patrick Tully
pstully@ucdavis

darrylo@hpsrlc.HP.COM (Darryl Okahata) (08/04/87)

In comp.sys.ibm.pc, ccs016@ucdavis.UUCP (Patrick Tully) writes:

> I've started using Turbo C recently. I've only glanced at the manual so I may
> have missed this. My question is what key do I hit to stop a endless loop. I've
> tried all the normal ones, break, escape, control break, etc ... but nothing.
>  
>   I have been writing many programs using rom-bios interupts, I don't know if
> this is what did it. The basic problem is when I hit a endless loop I can't get
> out, only by rebooting.
>  
> Patrick Tully
> pstully@ucdavis
> ----------

     The control-C/Break (control-Break) only works if you use DOS calls,
not ROM BIOS calls.  The reason for this is that DOS and only DOS checks to
see if the user has hit control-C/Break.  The ROM BIOS doesn't do jack
diddly squat (except for setting a flag).  Also, unless you execute the
"BREAK ON" command from command.com, DOS will only check for a
control-C/Break when DOS sends a character to the screen; with BREAK ON,
DOS will check for a control-C/Break every time a DOS call is made.

     In short, if your program is in an infinite loop and does not make any
DOS calls while in the loop, you're out of luck (unless you have special
software which allows you to break out of a program and return to DOS,
like the Periscope debugger).  If your program is in an infinite loop and
does make DOS calls, you can only break out if you've executed the "BREAK
ON" command or are making a DOS console output call.

     -- Darryl Okahata
	{hplabs!hpcea!, hpfcla!} hpsrla!darrylo
	CompuServe: 75206,3074

Disclaimer: the above is the author's personal opinion and is not the
opinion or policy of his employer or of the little green men that
have been following him all day.