0

I'm having difficulties in understanding why this code results in 3f000000.

float f = 5e-1;
printf("%x", *(int*)&f);
too honest for this site
  • 12,050
  • 4
  • 30
  • 52
smiljanic997
  • 81
  • 11
  • 7
    The result is undefined. This is violation of the [strict aliasing rule](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule). – Eugene Sh. Jul 11 '17 at 14:05
  • 1
    Do you know *anything* about floating pointer number or how they are stored on computers? About [the IEEE-754 standard](https://en.wikipedia.org/wiki/IEEE_754)? Continue with that after you read about strict aliasing (of which there are ways around). – Some programmer dude Jul 11 '17 at 14:05
  • 1
    Which result did you expect? – alk Jul 11 '17 at 14:08
  • Please try not to use both the `c++` and `c` tags. Those are two separate languages. – Ron Jul 11 '17 at 14:08
  • Read this literally: a float variable `f`, take its address (pointer to float), force it to pointer to int, get its contents (i.e. read the bits of the float as it were bits of an int), print it as hex number. This may work if `sizeof (int)` is `sizeof (float)` but that's not granted but compiler/platform dependend. – Scheff's Cat Jul 11 '17 at 14:09
  • You also have to understand endianness... – pmg Jul 11 '17 at 14:15

5 Answers5

9

This is undefined behavior: the standard does not guarantee pointers to int and float to have the same alignment, so (int*)&f cast is invalid (Q&A).

In your case, the cast produced a value that is consistent with IEEE-754 representation of 0.5 (5e-1) below:

bin:    0011 1111 0000 0000 0000 0000 0000 0000
        +--- ---- -=== ==== ==== ==== ==== ====
hex:       3    f    0    0    0    0    0    0

where + is the sign bit, - are exponent bits, and = are mantissa bits.

However, there is absolutely no guarantee that the same program is going to produce the same result when you run it on other systems, or even that the program is going to run to completion.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
6

You may prefer

void dump(const void *data, size_t len) {
    const unsigned char *x = data;
    printf("%02x", x[0]);
    for (size_t k = 1; k < len; k++) printf(" %02x", x[k]);
    puts("");
}

And then

float f = 5e-1;
dump(&f, sizeof f);
pmg
  • 106,608
  • 13
  • 126
  • 198
  • 1
    Just in case, there is a typo in the loop statement: `for (size_t k = 1; k < len, k++) { // the update part is separated with comma`. To work as expected the update part should be separated with semicolon: `for (size_t k = 1; k < len; k++) { // the update part is separated with semicolon` – Sergey Kudashev Aug 31 '23 at 22:10
3

The behaviour of your code is undefined due to (int*)&f. The C-style cast is invalid as the types are unrelated.

If you want to inspect the memory associated with f, then both C and C++ allow your to cast to const unsigned char*, and track through the memory with pointer arithmetic up to sizeof(f).

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
2

Since you are new to C / C++ - I guess - you may not have any ideas with respect to undefined behaviors. In short, there are some corners at which the C / C++ languages do not define what should happen exactly. Why? There are a lot of reasons behind, e.g. performance. In those cases, the results or effects of the behaviors are completely rely on implementations (compilers - more specifically (e.g. gcc, vc++)).

What you are doing here is listed at item 7 of the accepted answer to What are all the common undefined behaviours that a C++ programmer should know about?

duong_dajgja
  • 4,196
  • 1
  • 38
  • 65
  • There is no "C/C++ language". The question is about a C standard function, so it is safe to assume C only. – too honest for this site Jul 11 '17 at 15:09
  • "n those cases, the results or effects of the behaviors are completely rely on implementations" - That would be implementation defined behaviour. UB means the behaviour can depend on the weather, state of the sun or anything else. – too honest for this site Jul 11 '17 at 15:11
2

Others have already addressed the undefined behavior so I'll only address this part:

I'm having difficulties in understanding why this code results in 3f000000

The code tries to print the binary representation of the float value 0.5 (or 5e-1).

(it does that in an illegal way though - see other answers for the correct way - see this answer https://stackoverflow.com/a/45036945/4386427 )

The explanation for the value 3f000000 is that your system seem to use IEEE 754 single-precision binary floating-point format (see https://en.wikipedia.org/wiki/Single-precision_floating-point_format).

The format uses

  • bit 31 as sign bit (0 in your case)
  • bit 30..23 as exponent (01111110 binary = 7e hex = 126 decimal in your case)
  • bit 22..0 as fraction (all zero in your case)

So in your case

  • sign is 0
  • exponent is 126
  • fraction is 0

In general the value is calculated as:

value = (-1)^sign * (1 + fraction) * 2^(exponent - 127)

Since sign and fraction is 0, it is pretty easy to calculate the value:

value = 1 * 1 * 2^(126 - 127) = 2^-1 = 0.5

So with IEEE 754 single-precision binary floating-point a float with value 0.5 is stored with the binary pattern 3f000000

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63