0

scanf needs %lf for doubles and printf is okay with just %f

So, why is printf and scanf okay with %d?

This is what I think the reason is:

A floating point (%f) uses exactly 64 bits whereas a double floating-point number (%lf) uses at least 32. The compiler doesn't know how many bits to assign to a variable that is being scanned in by scanf, so we use %lf to tell the compiler that it needs to be at least 32 bits.

Okay... but then why do we use %d for both scanf and printf? Why not %ld and %d? %ld doesn't exist in C for starters. %d is a signed decimal number that needs at least 16 bits. You're already telling the compiler what the lower bound is in how many bits to allocate to it, so it is okay for scanf. This is also why we don't have a %ld.

Please do correct me if I am wrong or inform me what I can do to make this answer better. I'm pretty sure it is not a perfect answer.

Community
  • 1
  • 1
Frikster
  • 2,755
  • 5
  • 37
  • 71
  • 1
    Compiler does not have to do anything with %x. All in all `printf` and `scanf` are library functions that interprete format string and copy to `stdin`/from `stdout` from/to already allocated memory, using the specified format... – bbonev Feb 09 '14 at 03:20
  • float uses 64 bit but double float uses 32 ... ? Are you sure ? – X Tian Feb 09 '14 at 03:20
  • for `long %ld`, `long long %lld`, `short %hd` – BLUEPIXY Feb 09 '14 at 03:21
  • @XTian, Yes I think I have that wrong. Thank you. From wikipedia: "Double-precision floating-point (%lf) format is a computer number format that occupies 8 bytes (64 bits) in computer memory and represents a wide dynamic range of values by using floating point." - http://en.wikipedia.org/wiki/Double_precision_floating-point_format – Frikster Aug 19 '14 at 23:00

2 Answers2

2

You can think scanf as converting input stream into variables that defined in your code. Thus, scanf needs to know the exactly size for each variable. In general, the 32-bit and 64-bit IEEE 754 binary floating-point formats are used in C. So, %f means 32-bit and %lf means 64-bit.

Besides %ld exists and it means 32-bit integer. %lld also exists which means 64-bit integer. The above wiki site explains all C data types very well.

rookiepig
  • 489
  • 3
  • 12
1

See §6.5.2.2/6-7 in the C99 standard.

§6.5.2.2/6 defines the default argument promotions: (emphasis added)

the integer promotions are performed on each argument, and arguments that have type float are promoted to double.

and specifies that these promotions are performed on arguments to a function declared with no prototype (that is, with an empty parameter list () instead of (void), where the latter is used to indicate no arguments).

Paragraph 7 additionally specifies that if the prototype of the function has a trailing ellipsis (...):

The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments.

The integer promotions are defined in §6.3.1.1/2; they apply to

  • objects or expressions of an integer type whose "integer conversion rank is less than or equal to the rank of int and unsigned int": roughly speaking, any smaller integer type, such as boolean or character types;

  • bit-fields of type _Bool, int, signed int or unsigned int.

If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.

All other types are unchanged by the integer promotions.

In short, if you have varargs function, such as printf or scanf:

  • Integer arguments which are no larger than int are converted to (possibly unsigned) int. (This does not include long.)

  • Floating point arguments which are no larger than double are converted to double. (This includes float.)

  • Pointers are unaltered.

  • Other non-pointer types are unaltered.

So printf doesn't need to distinguish between float and double, because it will never be passed a float. It does need to distinguish between int and long.

But scanf does need to know whether an argument is a pointer to a float or a pointer to a double, because pointers are unchanged by the default argument promotions.

rici
  • 234,347
  • 28
  • 237
  • 341
  • My summary is simply that C will promote floats (%f) to doubles (%lf) all the time, but 16-bit integers (%d) are only converted to unsigned integers when an int cannot represent all values of the original type. Hence, scanf can accept %d, but not %f. Is this correct? I'd like to know if I finally have this correct. – Frikster Aug 19 '14 at 23:00
  • 1
    @DirkHaupt No, it's not correct. First, `scanf` can accept `%f`. Also `int` (`%d`) is not necessarily 16-bit, so that's irrelevant. The difference between `scanf` and `printf` is that `scanf` arguments are *pointers* and `printf` (numeric) arguments are *values*. Values are subject to standard promotions. Pointers are not, because you can't magically change what's being pointed at into a different format. So if you pass a `float` to `printf`, it will be promoted to a `double` before `printf` sees it. But if you pass a `pointer to float` to `scanf`, `scanf` needs to know that. – rici Aug 20 '14 at 03:08