[comp.lang.c] float to double pain

mikel@ritcsh.cs.rit.edu (Mike Leibow) (12/11/90)

On some machines, the floats in the following program are promoted to doubles,
and other machines, the floats remain floats.  I believe that these floats
shoud never look like doubles... What do you think?


check(af1)
float *af1; /* if this is "double," then this program works on most machines*/
{
	printf("%f\n", *af1);	/* and you'd have to change %f to %lf */
}

t(f1)
float f1;
{
	check(&f1);
}

main()
{
	t(4.0);
}


If you post a followup, I'll probably not see it because our news disk is
always full.  Please send me email...

	--Mike

mikel@ritcsh.cis.rit.edu

wirzeniu@cs.Helsinki.FI (Lars Wirzenius) (12/11/90)

In article <4268@ritcsh.cs.rit.edu> you write:

>check(af1)
>float *af1; /* if this is "double," then this program works on most machines*/
>{
>	printf("%f\n", *af1);	/* and you'd have to change %f to %lf */
>}

Here, *af1 in the call to printf is a float that gets promoted to a
double since it's used as a non-fixed argument to printf (i.e., as one
of those arguments that can vary from one call to another).  It is
impossible to pass a float as a non-fixed argument.  The same applies to
old-style functions.  These arguments go through "default argument
promotion".  This is described in K&R-2, Appendix A, Chapter 7.3.2, page
202, third paragraph (at least in my copy, your page number may wary).

By the way, %f for printf means double, there isn't any conversion
character for float (because of the reasons outlined above).

>t(f1)
>float f1;
>{
>	check(&f1);
>}

For old-style function definitions arguments of type float are silently
rewritten to be of type double. So &f1 is actually a pointer to a
double, which is inconsistent with check's expectation of a pointer to a
float. You need a cast here to make everything work properly. It may be that
your program is working only "by coincidence". Using new style function
prototypes and definitions would probably take care of your problem.

>main()
>{
>	t(4.0);
>}

4.0 is a constant of type double. Since t actually does expect a double,
everything should work OK as far as t is concerned..

>If you post a followup, I'll probably not see it because our news disk is
>always full.  Please send me email...

Done.

Lars Wirzenius    wirzeniu@cs.helsinki.fi    wirzenius@cc.helsinki.fi

tim@proton.amd.com (Tim Olson) (12/12/90)

In article <9919@hydra.Helsinki.FI> wirzeniu@cs.Helsinki.FI (Lars Wirzenius) writes:
| In article <4268@ritcsh.cs.rit.edu> you write:
| >t(f1)
| >float f1;
| >{
| >	check(&f1);
| >}
| 
| For old-style function definitions arguments of type float are silently
| rewritten to be of type double.

	Correct.

| So &f1 is actually a pointer to a
| double, which is inconsistent with check's expectation of a pointer to a
| float.

	This isn't right -- type-rewriting does not take place for
	pointers; &f1 is still a pointer to a float.


--
	-- Tim Olson
	Advanced Micro Devices
	(tim@amd.com)

tim@proton.amd.com (Tim Olson) (12/12/90)

In article <1990Dec11.173043.8171@mozart.amd.com> tim@amd.com (I) write:
| | >t(f1)
| | >float f1;
| | >{
| | >	check(&f1);
| | >}
| | 
| | For old-style function definitions arguments of type float are silently
| | rewritten to be of type double.
| 
| 	Correct.
| 
| | So &f1 is actually a pointer to a
| | double, which is inconsistent with check's expectation of a pointer to a
| | float.
| 
| 	This isn't right -- type-rewriting does not take place for
| 	pointers; &f1 is still a pointer to a float.

After writing this, it was pointed out to me by
wald@theory.lcs.mit.edu (David Wald) that I missed the fact that f1
was itself passed in as a parameter of type "float" with an old-style
declaration -- I had mistakenly thought it was declared locally.

To get back to the real question, then:
K&R compilers tended to keep arguments of type "float" silently
promoted to doubles, causing the problem that the original poster
pointed out.  ANSI-compliant compilers, however, must convert each
incoming argument to the type of its corresponding parameter (as if by
assignment).  This solves the type-mismatch problem, and makes much
more sense, as well!

Note that this is not limited to floats/doubles; "narrowing" must
occur for all types that have default widening rules, like char/short
-> int.  However, most K&R C compilers do the right thing with these.

--
	-- Tim Olson
	Advanced Micro Devices
	(tim@amd.com)