1

Right now I'm watching this lecture: https://www.youtube.com/watch?v=jTSvthW34GU In around 50th minute of the film he says that this code will return non-zero value:

float f = 7.0;
short s = *(short*)&f;

Correct me if I'm mistaking:

  1. &f is a pointer to float.
  2. We take &f and cast it to pointer to short.
  3. Then we dereference (don't know if it's a verb) that pointer so eventually the whole statement represents a value of 7.

If I print that it displays 0. Why?

JCob
  • 15
  • 2
  • 2
    This is just taking the bytes that `float` is stored as and interpreting them as a `short`. They have different layouts in memory; you can't do this and expect a meaningful result. – cdhowie Nov 11 '14 at 20:58
  • float is 4 bytes, short is 2 bytes. – Olayinka Nov 11 '14 at 20:59
  • try with a greater number than 7.0 – crashxxl Nov 11 '14 at 21:00
  • 1
    You can predict what it will be for any given architecture, if you know what float representation and endianness it uses, but you certainly can't make universal statements about the result. – AShelly Nov 11 '14 at 21:01
  • Ok, but still the part that short will copy from float includes some ones (does it?). It should be a non-zero value. – JCob Nov 11 '14 at 21:01
  • Which part will short copy from? - that's the question. – AShelly Nov 11 '14 at 21:02
  • @JCob You have no such guarantee. – cdhowie Nov 11 '14 at 21:02
  • So this is platform-dependent? – JCob Nov 11 '14 at 21:04
  • This is the very definition of platform-dependent. – Lee Daniel Crocker Nov 11 '14 at 21:07
  • This code (and the code in the accepted answer) causes undefined behaviour due to violation of the *strict aliasing rule*. Read more about strict aliasing [here](http://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule). The behaviour is not reliable on any platform, and it might not copy any part of the float. – M.M Nov 11 '14 at 23:24
  • a guaranteed method to get the integer value is : short int = (short int)floor(f); – user3629249 Nov 12 '14 at 00:28

3 Answers3

2

Dereferencing through a cast pointer does not cause a conversion to take place the way casting a value does. No bits are changed. So, while

float f = 7.0;
short s = (short)f;

will result in s having the integer value 7,

short s = *(short *)&f;

will simply copy the first 16 bits (depending on platform) of the floating point representation of the value 7.0 into the short. On my system, using little-endian IEEE-754, those bits are all zero, so the value is zero.

Lee Daniel Crocker
  • 12,927
  • 3
  • 29
  • 55
1

Floats are represented internally as 4byte floating point numbers (1 signal bit, 8 exponent bits, 23 mantissa bits) while shorts are 2byte integer types (two's compliment numbers). The code above will reinterpret the top two or bottom two bytes (depending on endianness) of the floating point number as an short integer.

So in the case of 7.0, the floating point number looks like:

0_1000000 1_1100000 00000000 00000000

So on some machines, it will take the bottom 2bytes (all 0s) and on others, it will take the top bytes (non-zero).

For more, see:

Floating-point: http://en.wikipedia.org/wiki/Floating_point

Endianness: http://en.wikipedia.org/wiki/Endianness

Unn
  • 4,775
  • 18
  • 30
  • Perhaps: Floats are represented internally as 4byte floating point numbers **in IEEE-754 single-precision floating point format** (1 signal bit, 8 exponent bits, 23 mantissa bits). Just for the sake of completeness and to provide makers for further research by any interested party. – David C. Rankin Nov 11 '14 at 21:17
0

Casting a pointer to a different type does not cause any conversion of the pointed-to value; you are just interpreting the pointed-to bytes through the "lens" of a different type.

In the general case, casting a pointer to a different pointer type causes undefined behavior. In this case that behavior happens to depend on your architecture.

To get a picture of what is going on, we can write a general function that will display the bits of an object given a pointer to it:

template <typename T>
void display_bits(T const * p)
{
    char const * c = reinterpret_cast<char const *>(p);

    for (int i = 0; i < sizeof(T); ++i) {
        unsigned char b = static_cast<unsigned char>(*(c++));

        for (int j = 0; j < 8; ++j) {
            std::cout << ((b & 0x80) ? '1' : '0');
            b <<= 1;
        }

        std::cout << ' ';
    }

    std::cout << std::endl;
}

If we run the following code, this will give you a good idea of what is going on:

int main() {
    float f = 7.0;
    display_bits(&f);
    display_bits(reinterpret_cast<short*>(&f));

    return 0;
}

The output on my system is:

00000000 00000000 11100000 01000000 
00000000 00000000 

The result you get should now be pretty clear, but again it depends on the compiler and/or architecture. For example, using the same representation for float but on a big-endian machine, the result would be quite different because the bytes in the float would be reversed. In that case the short* would be pointing at the bytes 01000000 11100000.

cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • Note that in *all* cases such strict-alias violations cause undefined behavior (the conversion to `char*` as you've done is legal). It's just that sometimes it seems to do what you want. – Mark B Nov 11 '14 at 21:13
  • "casting a pointer to a different pointer type causes undefined behavior." - only if alignment requirements are not met – M.M Nov 11 '14 at 23:23