Question Details

No question body available.

Tags

c floating-point printf undefined-behavior format-specifiers

Answers (3)

Accepted Answer Available
Accepted Answer
January 20, 2026 Score: 6 Rep: 234,208 Quality: Expert Completeness: 80%

This behavior is of course not defined by the C standard, but what you observe is a common outcome due to how arguments are passed.

In many computing environments, the specification for passing arguments to routines says that integer and pointer arguments are passed in the general processor registers and floating-point arguments are passed in floating-point registers. (There are further rules for passing more arguments than fit in the registers, arguments that are too large for one register, and so on.) Then what happens is:

  • For printf("%f\n",5.0/4);, the address of the string "%f\n" is put into a general processor register, and the double value 1.25 is put into a floating-point register.
  • printf is called, and it takes the string from the general register, sees it needs a floating-point argument for the %f, takes the value from the floating-point register, formats it, and prints the result. Then printf returns.
  • For printf("%f\n",5/4);, the address of the string "%f\n" is again put into a general register. Then, since 5/4 has type int, its value, 1, is put into another general register. The floating-point register is left unchanged.
  • printf is called, and it again sees it needs a floating-point argument for the %f. So it takes it from the floating-point register. Since this register has not changed, it still contains 1.25, and printf formats that and prints the result.

When you comment the first line, 5.0/4 is never passed to printf in the first place, so it is never put into a floating-point register. Then the printf("%f\n",5/4); gets the contents of that register, which contains 0 likely because that was put there when the program was started up.

It should be noted that printf is a variadic function—the number of its arguments and their types are not fixed. It adapts to diverse arguments based on the format string. In code that calls the function, the compiler determines how to pass the arguments based on their types. This is different from functions that have their argument-parameter types fully specified. When such a function is called, the compiler checks that each argument matches the corresponding parameter type and either complains if it does not or converts it if suitable. So when a non-variadic function is passed an int value for a double parameter, the compiler converts the value and passes it in the correct place for a double argument.

January 20, 2026 Score: 4 Rep: 391,878 Quality: Medium Completeness: 60%

[It turns out that this doesn't answer the question, but it contains useful information for readers that might end up here, so I'm leaving it in place.]

First of all, 1.250000 is not expected. Dividing a value with an integer type by a value with an integer type uses integer division. This means that 5/4 produces int 1 (unlike 5.0/4, which produces double 1.25). If the the printf correctly displayed the results, we should expect 1.000000.

As for why the printf doesn't correctly print the result, printf %f expects a double, but you are providing an int. This results in a program with undefined behaviour.

Enable your compiler's warnings! It should have told you about this error. With gcc, I use -Wall -Wextra -pedantic.

$ gcc -Wall -Wextra -pedantic a.c -o a a.c: In function ‘main’: a.c:6:14: warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’ [-Wformat=] 6 | printf("%f\n",5/4); | ~^ ~~~ | | | | | int | double | %d
January 20, 2026 Score: 4 Rep: 233,990 Quality: Medium Completeness: 80%

The constant expression 5/4 has type int since both operands have that type. You then pass the result of this expression to printf with a %f format specifier which expects a double. Using the wrong format specifier in a printf call triggers undefined behavior in your code.

As for what is probably happening in this particular case, it has to do with the difference with how floating point types are passed as arguments to a function verses integer types.

On modern 64-bit systems, integers parameters are placed in general purpose registers while floating point parameters are placed in floating point registers. When you first call printf with 5.0/4 as the parameter, this expression has floating point type and is placed in a floating point register which is subsequently read when.

When you then call printf again with 5/4 as the argument, this is placed in a general purpose register. printf then sees the %f format specifier and reads from a general purpose register which still has the value that was placed there from the prior call which is what printed.

In contrast, without the first call to printf, the floating point register contains some other value, in this case 0, and that is what is printed.

But again, this is undefined behavior. The C standard imposes no requirements on what your program will do, so there is no guarantee of any particular behavior.