[comp.lang.c] Problem with printf

croes@imec.uucp (Kris Croes) (10/04/88)

Hello NetLand, 

May I introduce to you...
A little program containing a big problem.
  main()
  {
  int i = 17;
  float f = 17.0;

  printf("%d %f\n",i,i); /*1*/
  printf("%d %f\n",f,f); /*2*/
  }

Its output is:
17 0.000000
17032 0.000000
      ^^^^^^^^ Shouldn't this be 17.00000 ?

I am working under Ultrix 2.2, on a VAX-780 and had the same problem on
Apollo. BTW sizeof(int) = sizeof(float) = 4 on both machines.

Some tests (e.g. printing on several lines) showed that the problem is
caused by printing the float under the "%d" format. I know that
normal people don't do such a thing, but that is no reason for printf()
to mess up the stack. (???)

I know that not all binary numbers are valid floats. But if this was
the case, it would give problems in line /*1*/.

Why do things go wrong in line /*2*/ ? Is this a bug in my little
program, in printf(), in C , or where ?

K. Croes
-- 
--------
K. CROES - IMEC - Leuven - Belgium   ..!prlb2!imec!croes

The Demon King sends a "rm -r /" to your shell.

tomp@nikhefk.UUCP (Tom Ploegmakers) (10/06/88)

In article <504@imec.UUCP> croes@imec.UUCP (Kris Croes) writes:
>  main()
>  {
>  int i = 17;
>  float f = 17.0;
>
>  printf("%d %f\n",i,i); /*1*/
>  printf("%d %f\n",f,f); /*2*/
>  }
>
>Its output is:
>17 0.000000
>17032 0.000000
>      ^^^^^^^^ Shouldn't this be 17.00000 ?
>

This one has bitten me once too.
The problem is that floats are not passed to functions on the stack, but by
passing a pointer. That is, sometimes, you should check your compiler.

To make it work use:
  printf("%d %f\n",i,(float)i); /*1*/
  printf("%d %f\n",(int)f,f); /*2*/

Suc6.

tom ploegmakers		NIKHEF/K-CSG	(tomp@nikhefk.uucp)	

			po.box 4395, 1009 AJ Amsterdam, the Netherlands.
-- 

tom ploegmakers		NIKHEF/K-CSG	(tomp@nikhefk.uucp)	

			po.box 4395, 1009 AJ Amsterdam, the Netherlands.

dik@uva.UUCP (Casper H.S. Dik) (10/06/88)

In article <504@imec.UUCP> croes@imec.UUCP (Kris Croes) writes:
>Hello NetLand, 
>
>May I introduce to you...
>A little program containing a big problem.
>  main()
>  {
>  int i = 17;
>  float f = 17.0;
>
>  printf("%d %f\n",i,i); /*1*/
>  printf("%d %f\n",f,f); /*2*/
>  }
>
>Its output is:
>17 0.000000
>17032 0.000000
>      ^^^^^^^^ Shouldn't this be 17.00000 ?
>
No wonder, float arguments in C are converted to doubles before being passed
to functions. So printf expects sizeof(int)+sizeof(double) bytes but gets
sizeof(double)+sizeof(double). Since sizeof(double) > sizeof(float) this
results in printf interpreting garbage as data, thus resulting in
GIGO (Garbage In, Gospel Out).

If you had read the entire printf manual, you would have been put on the
right track by the explanation of %f '... converts the float or double 
argument ...'.

BTW you posted to the wrong news group. Printf is a standard C function
and the proper newsgroup would be comp.lang.c.

____________________________________________________________________________
Casper H.S. Dik
Student
University of Amsterdam     |		      dik@uva.uucp
The Netherlands             |                 ...!uunet!mcvax!uva!dik
____________________________________________________________________________
Casper H.S. Dik
University of Amsterdam     |		      dik@uva.uucp
The Netherlands             |                 ...!uunet!mcvax!uva!dik

maart@cs.vu.nl (Maarten Litmaath) (10/07/88)

In article <504@imec.UUCP> croes@imec.UUCP (Kris Croes) writes:
\Hello NetLand, 
\
\May I introduce to you...
\A little program containing a big problem.
\  main()
\  {
\  int i = 17;
\  float f = 17.0;
\
\  printf("%d %f\n",i,i); /*1*/
\  printf("%d %f\n",f,f); /*2*/
\  }

I have seen various explanations, none of them pointing out the ONLY error:

	if you're telling printf() to expect an int (%d), SUPPLY it an int,
	instead of a float!
-- 
Hippic sport:                         |Maarten Litmaath @ Free U Amsterdam:
             a contradiction in terms.|maart@cs.vu.nl, mcvax!botter!maart

limes@ouroborous (Greg Limes) (10/08/88)

In article <504@imec.UUCP>, croes@imec (Kris Croes) writes:
>  int i = 17;
>  float f = 17.0;
>
>  printf("%d %f\n",i,i); /*1*/
>  printf("%d %f\n",f,f); /*2*/

>Its output is:
>17 0.000000
>17032 0.000000
>      ^^^^^^^^ Shouldn't this be 17.00000 ?

Nope. You put a floating point number in the arg list, there is no guarantee
that printf, expecting an integer, will do the right thing. Try:

   printf("%d %f\n", i, (float)i);
   printf("%d %f\n", (int)f, f);

I expect that the float is being promoted to a double, which is taking up more
space than an integer. Assuming 32 bit integers, 32 bit floats, and 64 bit
doubles (not unreasonable), and arguments passed in memory, the %d would pick up
the first 32 bits of the double precision 17.0 (==17032), and the %f would pick
up the second 32 bits of the first double and the first 32 bits of the second
double.

In short, "printf" did not screw up your stack. "main" did, by passing badly
typed parameters.
-- 
Greg Limes [limes@sun.com]		semper ubi, sub ubi

gwyn@smoke.ARPA (Doug Gwyn ) (10/08/88)

In article <504@imec.UUCP> croes@imec.UUCP (Kris Croes) writes:
>  printf("%d %f\n",i,i); /*1*/
>Some tests (e.g. printing on several lines) showed that the problem is
>caused by printing the float under the "%d" format. I know that
>normal people don't do such a thing, but that is no reason for printf()
>to mess up the stack. (???)

It wasn't printf that messed up the stack,
it was you -- by not meeting the requirements
for using printf.
The arguments MUST match the corresponding
conversion specifiers in the format string.

ark@alice.UUCP (Andrew Koenig) (10/08/88)

In article <504@imec.UUCP>, croes@imec.uucp (Kris Croes) writes:
> Hello NetLand, 
 
> May I introduce to you...
> A little program containing a big problem.
>   main()
>   {
>   int i = 17;
>   float f = 17.0;
 
>   printf("%d %f\n",i,i); /*1*/
>   printf("%d %f\n",f,f); /*2*/
>   }
 
> Its output is:
> 17 0.000000
> 17032 0.000000
>       ^^^^^^^^ Shouldn't this be 17.00000 ?


A float is automatically cast to double when used as an argument.
Thus f probably takes up two words on the stack and %d picks off
only one.


Why do you want to use %d to print a float anyway?


Incidentally, the %g format is usually more useful than %f.
-- 
				--Andrew Koenig
				  ark@europa.att.com

ok@quintus.uucp (Richard A. O'Keefe) (10/10/88)

In article <429@nikhefk.UUCP> tomp@nikhefk.UUCP (Tom Ploegmakers) writes:
>This one has bitten me once too.
>The problem is that floats are not passed to functions on the stack, but by
>passing a pointer.

The problem is simply that when you pass a parameter to any function in
pre-ANSI C, or to a function for which no prototype is in scope in dpANS C,
(or in the "..." part of a call to a function which takes a variable
number of arguments, such as printf()), the compiler is obliged to widen
integral expressions to 'int' and floating-point expressions to 'double'.
Thus when you do
	printf("...%d...%f...", f, f)
f is widened to double:  it is as if you did
	printf("...%d...%d...", (double)f, (double)f)

Look up "argument conversions" in your favourite C textbook
(page 135 in Harbison & Steele).

If all else fails, it sometimes pays to look at the code your compiler
generates.  UNIX "C" compilers have a "-S" flag.  Or you can use a
debugger on the object file.

rosalia@mozart.UUCP (Mark Galassi) (10/11/88)

In article <504@imec.UUCP> croes@imec.UUCP (Kris Croes) writes:
>A little program containing a big problem.
>  int i = 17;
>  float f = 17.0;
>  printf("%d %f\n",i,i); /*1*/
>  printf("%d %f\n",f,f); /*2*/
>  }

Isn't it the case that the compiler promotes a float to a double
(64bits on a VAX probably), thus making the stack different from what
you thought it would be.

I believe that that must be the case, because when you call sin(x) and
x is just a float, it must be coerced to a double since the sin() func
is written to take a double.
-- 
						    Mark Galassi
						rosalia@mozart.UUCP
	These opinions are mine and should be everybody else's :-)