How to cast double to float pointer?

Viewed 10173

I'm trying to cast double to float pointer but I don't know the proper way to do it.

Here's my code

#include <iostream>

int main(int argc, const char * argv[]) {
    // insert code here...


    float *f;
    double d = 10;

    f = reinterpret_cast<float*>(&d);
    d = 20;

    std::cout << "RESULT : " << *f << std::endl;
    return 0;
}

And I get the following result.

RESULT : 0
Program ended with exit code: 0

How do I properly cast double to float pointer?

ADD : The result I expect to get is 20

5 Answers

Consider:

#include <cstdio>
#include <cassert>

using namespace std;

int main()
{
    double d = 10;
    float f;
    assert( sizeof d == 8 );
    assert( sizeof f == 4 );

    unsigned char * d_ = (unsigned char *)&d;
    printf( "%hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n", d_[0], d_[1], d_[2], d_[3], d_[4], d_[5], d_[6], d_[7] );
}

This, at least on my machine, gives the following output:

0 0 0 0 0 0 24 40

Explanation:

That is the internal representation of a double with value 10.

By casting the double * to float *, you are only looking at the first four bytes of this -- 0 0 0 0. Do you see why you are getting a 0 output when you dereference the pointer?

(Aside from, as others have pointed out, the dereferencing of the pointer being undefined behaviour due to breaking strict aliasing.)

Solution:

What you probably want is to cast the value of d:

static_cast<float>(d);

You can then store that value in an object of the correct type:

float f = static_cast<float>(d);
float * fp = &f;

Your code for casting the pointer is correct.

The mistake is *f, which causes undefined behaviour by violating the strict aliasing rule. You can not read or write through a pointer that has the wrong type for the object it points to. (with a small list of exceptions).

The behaviour is undefined: the language offers no way of doing this. For example, sizeof(float*) does not have to be the same as sizeof(double*). C++ aims to maximise flexibility.

You are allowed to cast the address of a double to a const unsigned char* pointer and read the memory that way.

Otherwise you need to resort to assembly, where at the CPU level, the distinction between a pointer to a type and an integral type is considerably blurred.

If you want to convert a double to a float, then write

double d = 10; float f = d;

What you want to do is a narrowing static_cast:

auto f = static_cast<float>(d);
float* pointer = &f;

The use of reinterpret_cast will fail, because it will not issue the compiler to change the bitwise representation of a double to that one of a float. It literally will reinterpret the double value as a float, yielding weird and undefined results as the representations differ. static_cast on the other side will take care for you that the representations are adjusted correctly, possibly truncating the least significant bits if necessary. After this, you can safely use the address of the float variable and access the value with a pointer.

The behavior you want can be implemented in C++. Not via a raw pointer, though, but C++ allows user-defined types.

class double_as_float {
  double& d;
public:
  double_as_float(double& d) : d(d) { }
  float operator*() const { return static_cast<float>(d); }
};

Usage:

#include <iostream>
int main() {

    double d = 10;

    double_as_float f { d };
    d = 20;

    std::cout << "RESULT : " << *f << std::endl;
    return 0;
}
Related