-2

Trying to print float number in hexadecimal format:

int main() {
    float a = 1.1;
    printf("%f %X\n", a, a);
}

For some reason printf returns this:

1.100000 A878DAC8 // hex number is random every time

It should be 3F8CCCCD. Why does it have such behavior?

  • Why do you think it should be `3F8CCCCD` ? – Eugene Sh. Aug 15 '19 at 19:22
  • 2
    Because 1.1 in hex is 3F8CCCCD and this value stored in stack (i checked) – Yevhen Grushko Aug 15 '19 at 19:25
  • 6
    Passing a `float` value to `printf` and trying to print it using `%X` will give you neither the hexadecimal representation of the float, nor an integer approximation of the value. It will give you, as you have seen, a meaninglessly random result. Try using `*(int32_t *)&a`, for a start. – Steve Summit Aug 15 '19 at 19:26
  • 3F8CCCCD is an integer value. Where do you think the code to convert 1.1 from a floating point value to an integer value is? I don't see anything to do that in the code you pasted. You're just telling the implementation to pretend you're giving it a hexadecimal integer when you're not. Who knows what that will do. Maybe your platform passes `float`s in different registers. – David Schwartz Aug 15 '19 at 19:30
  • Doesn't your compiler shoots warnings ? My compiler doesn't allow to compile. `format ‘%x’ expects argument of type ‘unsigned int’, but argument 2 has type ‘double’ [-Werror=format=]` Its good to listen to compiler warning first and then play with it. Compile with flag like `-Wall` `-Werror` – Achal Aug 15 '19 at 19:35
  • Your question asks “Why does it have such behavior?” Is that really what you want to know, or do you want to know how to print, using hexadecimal, the bytes that represent the `float` object? – Eric Postpischil Aug 15 '19 at 19:37
  • @axiac I understand that you can figure that out. But nowhere does your code accomplish that conversion. To produce "3F8CCCD", somewhere that bit representation must be re-interpreted as a representation of an integer. Where does your code perform that re-interpretation? It does not do it. So the code doesn't work. (For example, it might need to be moved from a floating point register to an integer register. Or it might need something else. Regardless, whatever it needs, you need some code that clearly does whatever is needed for that to happen. You have none.) – David Schwartz Aug 15 '19 at 19:40
  • yes i want to understand how does everything work – Yevhen Grushko Aug 15 '19 at 19:48
  • This value ("3F8CCCD") is already in memory. I dont understand why i should do some reinterpretation? Printf doesnt know if i interpeted this value as float or as integer for printf it is only bytes that are interpreted as integer. Right? – Yevhen Grushko Aug 15 '19 at 20:13
  • 1
    @YevhenGrushko absolutely wrong. – Antti Haapala -- Слава Україні Aug 15 '19 at 20:54
  • This probably converts the `float` to a `double` and then passes that. That would explain the changed value. – S.S. Anne Aug 15 '19 at 21:57
  • 3
    The fact that you're seeing random values likely means you're using a target that DOESN'T pass args on the stack, such as x86_64, which passes them in registers. So you're seeing the value from some unused integer register (the value is in an fp register). – Chris Dodd Aug 16 '19 at 00:12
  • Omg, that is the answer to my question! Thank you! You can write answer and ill check it as the best answer! – Yevhen Grushko Aug 16 '19 at 08:20

2 Answers2

2

The explanation for the observed behavior is given in Govind Parmar's answer. Note that you might get the behavior you expect with this modified program, assuming 32-bit ints and floats:

#include <stdio.h>
#include <string.h>

int main() {
    int i;
    float a = 1.1;
    memcpy(&i, &a, sizeof(i));
    printf("%f %X\n", a, i);
    return 0;
}

Output: 1.100000 3F8CCCCD

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
chqrlie
  • 131,814
  • 10
  • 121
  • 189
1

The problem is that you have invoked undefined behavior, so it is hard to answer "why" you are seeing this output, because the language makes no promises at this point.

The correct format specifier for a float or double is %f. The specifier %x expects an integral value, which may be passed in a completely different way than floating point values on your platform. If these arguments are passed as variadic arguments (like the ... parameter of printf), where the only indication of type is from the format string, and the format string gets the type wrong, it may be reading a garbage value.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
  • So as i uderstand, the reason why this happenes because printf cant get proper vlaue? But i cant understand why? I checked stack. There is no difference between puting int or float in stack. They are both 4 bytes value that locates in same position. – Yevhen Grushko Aug 15 '19 at 19:44
  • @YevhenGrushko That was just one possible explanation for this unpredictable output, off the top of my head. It's really pointless to reason about undefined behavior. The correct response to learning that your code invokes undefined behavior is to remove the undefined behavior. – Govind Parmar Aug 15 '19 at 20:02
  • What specific undefined behavior i invoked? I cant find my situation in your link. – Yevhen Grushko Aug 15 '19 at 20:25
  • @YevhenGrushko You passed `%x` as a format specifier and then used a variable of type `float` to satisfy that argument in the format string. This is undefined behavior. – Govind Parmar Aug 15 '19 at 20:27
  • @YevhenGrushko idk where you've learnt about this "stack" but it isn't actually how C works. The implementation might use stack or not. First of all you should read in a C book what `...` does for arguments. You're not passing `float` anywhere, but a `double`. – Antti Haapala -- Слава Україні Aug 15 '19 at 20:57
  • Type of the variable is float but the type of the argument is double. ;) – Antti Haapala -- Слава Україні Aug 15 '19 at 21:00