Inhalt

C Default Argument Promotions

Have you ever wondered why your application never crashes, shows strange behavior, or does not print the correct double precision numbers, when you write something like

float  f = 1.1f;
double d = 1.1;

printf("float  = %f\n", f);
printf("double = %f\n", d);

This would print following result

float  = 1.100000
double = 1.100000

and works like you normally expect it.

But then why the question above? The %f format specifier for the printf/scanf class of functions denotes a variable of type float which consumes 32 bits. In the example above d is of type double which uses 64 bits and actually requires %lf. The provided argument d (64 bits) would be interpreted as a variable of type float (32 bits). If this would happen, then the output would look more like that (at least on architectures using little endian byte order):

float  = 1.100000
double = -0.000000

The double variable d is stored in memory as:

0x9a 99 99 99 99 99 f1 3f 

As little endian byte order is used dwill finally be interpreted as:

0x3f f1 99 99 99 99 99 9a

When only the first four bytes would be considered by printf then these bytes would be 0x9a 99 99 99 (from memory) and interpreted as float which would represent the number (ca.) -1.58818684e-23 (0x99 99 99 9a). Printed with %f gives -0.000000. But nothing of this happens and everything works like expected.

The reason is that ONLY the printf class of functions treat %f as %lf, which denotes a double precision argument. Accordingly this is also done for %g and %e. So why can printf safely do this?

The reason are the default argument promotions from C. During this following casts take place (without guarantee to be complete):

char, short   to   int
unsigned char, unsigned short   to   unsigned int
float   to   double

The promotions are applied to

  • all parameters of a function, when no prototype for this function exists and
  • to all non-declared parameters of variadic functions, i.e. functions which take a variable number of arguments.

As the printf class of functions are variadic (denoted by the elipsis „…“ in the function signature) the default argument promotions take place. Finally the call printf("float = %f\n", f) will after promotion look like printf("float = %f\n", (double)f) and printf can safely assume that every %f, %g, and %e denotes a parameter of type double.

References:

  • Michael L. Overton. Numerical Computing with IEEE Floating Point Arithmetic, SIAM, 2001. Chapter 10: Floating Point in C.
  • C Standard. Chapter 6.5.2.2 (http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1124.pdf)
  • Stackoverflow – Default argument promotions in C function calls (http://stackoverflow.com/questions/1255775).