tags:

views:

2016

answers:

13
#include <stdio.h>

int main() {
    float a = 1234.5f;
    printf("%d\n", a);
    return 0;
}

It displays a 0!! How is that possible? What is the reasoning?


I have deliberately put a %d in the printf statement to study the behaviour of printf.

A: 

It's not an integer?

Try using %f

Tangrs
yes, I know. I have deliberately put a `%d` there.
Lazer
For what reason?
Tangrs
I guess the question is, why doesn't it just convert the float to int and display "1234"?
Space_C0wb0y
don't expect c not to let you do something that makes no logical sense. Yes many languages would give the 1234 you may expect, and maybe even some implementations of c will i don't think this behavior is defined. C lets you hang yourself its like the parent that lets you try crack for the hell of it.
rerun
Because C is designed to be flexible.
Tangrs
A: 

You want %f not %d

S.C. Madsen
+1  A: 

%d is decimal

%f is float

see more of these here.

You are getting 0 because floats and integers are represented differently.

Filip Ekberg
+5  A: 

It's because of the representation of a float in binary. The conversion to an integer leaves it with 0.

Shaihi
You seem to be the only one that understood what he was asking for. Unless Im mistaken myself of course.
mizipzor
No, he's wrong anyway
Charlie Somerville
I agree that the answer is inaccurate and incomplete, but not wrong.
Shaihi
+15  A: 

The %d specifier tells printf to expect an integer. So the first four (or two, depending on the platform) bytes of the float are intepreted as an integer. If they happen to be zero, a zero is printed

The binary representation of 1234.5 is something like

1.00110100101 * 2^10 (exponent is decimal ...)

With a C compiler which represents float actually as IEEE754 double values, the bytes would be (if I made no mistake)

01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000

On an Intel (x86) system with little endianess (i.e. the least significant byte coming first), this byte sequence gets reversed so that the first four bytes are zero. That is, what printf prints out ...

See This Wikipedia article for floating point representation according to IEEE754.

MartinStettner
+4  A: 

The reason is that printf() is a pretty dumb function. It does not check types at all. If you say the first argument is an int (and this is what you are saying with %d), it believes you and it takes just the bytes needed for an int. In this case, asuming your machine uses four-byte int and eight-byte double (the float is converted to a double inside printf()), the first four bytes of a will be just zeroes, and this gets printed.

Gorpik
+5  A: 

Because you invoked undefined behaviour: you violated the contract of the printf() method by lying to it about its parameter types, so the compiler is free to do whatever it pleases. It could make the program output "dksjalk is a ninnyhead!!!" and technically it would still be right.

Kilian Foth
+3  A: 

It won't convert automatically float to integer. Because both has different format of storage. So if you want to convert, use (int) typecasting.

#include <stdio.h>

int main() {
    float a = 1234.5f;
    printf("%d\n", (int)a);
    return 0;
}
sganesh
+143  A: 

That's because %d expects an int but you've provided a float.

Use %e/%f/%g to print the float.


On why 0 is printed: The floating point number is converted to double before sending to printf. The number 1234.5 in double representation in little endian is

00 00 00 00  00 4A 93 40

A %d consumes a 32-bit integer, so a zero is printed. (As a test, you could printf("%d, %d\n", 1234.5f); You could get on output 0, 1083394560.)


As for why the float is converted to double, as the prototype of printf is int printf(const char*, ...), from 6.5.2.2/7,

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.

and from 6.5.2.2/6,

If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions.

(Thanks Alok for finding this out.)

KennyTM
+1, great answer :)
mizipzor
+1 Best answer. It answers both "standard technically correct" why and "your likely implementation" why.
Chris Lutz
I believe you are the only one of 12 people who actually provided the answer he was looking for.
Gabe
@KennyTM: why is floating point number converted to `double` before sending to `printf`?
Lazer
Because `printf` is a variadic function, and the standard says that for variadic functions, a `float` is converted to `double` before passing.
Alok
I just checked the book (Stroustup). It says that this (conversion from float to double) only happens if `"the arguement has not been declared"`. In my example - I have declared `a`. Where am I going wrong?
Lazer
From the C standard: "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." and "...and arguments that have type float are promoted to double. These are called the *default argument promotions*."
Alok
+1 KennyTM this is precisely what I mean by deeeeeeep knowledge!! Hats off!!
TheMachineCharmer
The very fact that one can write `printf("%d, %d\n", 1234.5f);` makes me extremely wary of the method...
Matthieu M.
@Matthieu: gcc by default would throw warnings if the format string and the input parameters' types do not match.
KennyTM
Keeping all this in mind, how does a `printf("%f\n", a); //%f instead of %d` manage to print `1234.500000`? Shouldn't it also be printing a `0.000000`?
Lazer
@dksjalk: `%f` consumes a double (64-bit) instead of an int.
KennyTM
@KennyTM: thanks! I just realised that there are no separate string formats for printing single precision (`float`) and double precision (`double`) floating point (for use with `printf`)
Lazer
Using incorrect format specifier in `printf()` invokes **Undefined Behaviour**.
Prasoon Saurav
@dksjalk: this is because `printf` cannot be passed a `float`. By the time `printf` sees it, it's already a `double`.
Alok
Great Answer...........
Karandeep Singh
+1  A: 

Since you tagged it with C++ as well, this code does the conversion as you probably expect:

#include <iostream.h>

int main() {
    float a = 1234.5f;
    std::cout << a << " " << (int)a << "\n";
    return 0;
}

Output:

1234.5 1234
mizipzor
+22  A: 

Technically speaking there is no the printf, each library implements its own, and therefore, your method of trying to study printf's behavior by doing what you are doing is not going to be of much use. You could be trying to study the behavior of printf on your system, and if so, you should read the documentation, and look at the source code for printf if it is available for your library.

For example, on my Macbook, I get the output 1606416304 with your program.

Having said that, when you pass a float to a variadic function, the float is passed as a double. So, your program is equivalent to having declared a as a double.

To examine the bytes of a double, you can see this answer to a recent question here on SO.

Let's do that:

#include <stdio.h>

int main(void)
{
    double a = 1234.5f;
    unsigned char *p = (unsigned char *)&a;
    size_t i;

    printf("size of double: %zu, int: %zu\n", sizeof(double), sizeof(int));
    for (i=0; i < sizeof a; ++i)
        printf("%02x ", p[i]);
    putchar('\n');
    return 0;
}

When I run the above program, I get:

size of double: 8, int: 4
00 00 00 00 00 4a 93 40 

So, the first four bytes of the double turned out to be 0, which may be why you got 0 as the output of your printf call.

For more interesting results, we can change the program a bit:

#include <stdio.h>

int main(void)
{
    double a = 1234.5f;
    int b = 42;

    printf("%d %d\n", a, b);
    return 0;
}

When I run the above program on my Macbook, I get:

42 1606416384

With the same program on a Linux machine, I get:

0 1083394560
Alok
+1  A: 

hey it had to print something so it printed a 0. Remember in C 0 is everything else!

sid
How is it so? In C there is no such thing as everything else.
Vlad
if x is something, then !x == 0 :)
sid
if(iGot=="everything") print **"everything"; else** print "nothing";
nik
+1  A: 

You just need to use the appropriate format specifier (%d,%f,%s,etc.) with the relevant data type (int,float, string, etc.).

Maxood
The question is not how to fix it but why it works the way it works.
ya23