tags:

views:

291

answers:

3

Hi I'm trying to convert from an int to a float in C and for some reason the cast changes the value and I'm not sure why. So:

fprintf (stderr, "%d,%d\n", rgbValues->green, (float)rgbValues->green);

produces two different numbers. Note that rgbValues->green is an int.

Any idea why this is happening?

Thanks

+11  A: 

You have to say that in your format string. Use:

fprintf(stderr, "%d,%f\n", rgbValues->green, (float)rgbValues->green);
                     ^

instead of:

fprintf(stderr, "%d,%d\n", rgbValues->green, (float)rgbValues->green);
                     ^

Note the change from d to f (the circumflex ^ isn't part of the code, just an indicator as to where to look).

AraK
What? This is the exact same (wrong) code as the OP.
Adam Rosenfield
The comment line on top is probably meant to indicate the change to be made. `fprintf(stderr, "%d,%f\n", rgbValues->green, (float)rgbValues->green);` is what it should be.
hexium
@Adam Read the comment.
phoebus
I see the comment -- that doesn't make the code any less wrong.
Adam Rosenfield
@Adam I hope you see that `%f` is meant to be replaced with `%d`. That's why I put `%f` *exactly* above `%d`.
AraK
I'm with Adam, that just looks weird. It's right, but weird.
Carl Norum
@AraK: Actually you want to say that %d is meant to be replaced with %f... :)
sth
Of course I see that. My point is that you should actually spell out what the correct code is, not copy the wrong code and awkwardly indicate the change to be made.
Adam Rosenfield
@Adam I see your point. I though this "one letter" change wouldn't be clear. Thats why I tried to make it clear in the above comment.
AraK
There ya go, that should hopefully make it a bit more obvious to all.
paxdiablo
@pax Thanks, It is much better now :)
AraK
A: 

Expanding on @AraK's answer, you're casting once to float, and then printf is interpreting that bit pattern as an int in the format specifier string. It's doing exactly what you're telling it to do :)

If you want to only cast to float - do this:

// format specifier is %d for int, %f for float
// show the cast value of rgbValues->green as well as its "real" value
fprintf(stderr, "%d,%f\n", rgbValues->green, (float)rgbValues->green);

Edit - wording based on comments

warren
It's essential to note, however, that they are different types of casts: the first cast converts the integer value to a floating point value, but the second *reinterprets the floating point value* as if it were an integer.
James McNellis
It's not really a double-cast, `printf()` has no idea that your number is a `float`, so it can't cast it back to an `int` (which would do the right thing and print the same number twice). It's just interpreting the bit pattern you sent it (a floating point number) as an integer (since that's what you told it it was in the format string), and printing garbage.
Carl Norum
@Carl - you're right, that's better wording than how I said it :)
warren
+5  A: 

The %d format specifier says to printf, "take the next 4 bytes off of the stack, interpret them as an integer, and print out that integer." Since you're actually passing a float as a parameter, the bytes of the float (which are stored in IEEE-754 format) are getting misinterpreted as an integer, hence the different values. (Actually, the float is getting converted to a double due to argument promotion within variadic functions, and it's the first 4 bytes of that promoted double that are getting interpreted as an integer.)

The correct solution is to use one of the %e, %f, or %g format specifiers instead of %d when printing out a float. %e says, "take the next 8 bytes off the stack, interpret them as a double, and print it out using scientific (exponential) notation" %f prints out using a fixed-point format, and %g prints out whichever would be shorter of %e or %f.

fprintf(stderr, "%d,%f\n", rgbValues->green, (float)rgbValues->green);
Adam Rosenfield