Search code examples
c++compiler-construction

Why can't I put a float into a ptr of any type without any kind of conversion going on?


I'm currently writing a runtime for my compiler project and I want general and easy to use struct for encoding different types (the source language is scheme).

My current approach is:

struct SObj {
    SType type;
    uint64_t *value;
};

Pointer are always 64 or 32 bit wide, so shouldn't it be possible to literally put a float into my value? Then, if I want the actual value of the float, I just take the raw bytes and interprete them as a float.

Thanks in advance.


Solution

  • Not really.

    When you write C++ you're programming an abstraction. You're describing a program. Contrary to popular belief, it's not "all just bytes".

    Compilers are complex. They can, and will, assume that you follow the rules, and use that assumption to produce the most efficient "actual" code (read: machine code) possible.

    One of those rules is that a uint64_t* is a pointer that points to a uint64_t. When you chuck arbitrary bits into there — whether they are identical to the bits that form a valid float, or something else — it is no longer a valid pointer, and simply evaluating it has undefined behaviour.

    There are language facilities that can do what you want, like union. But you have to be careful not to violate aliasing rules. You'd store a flag (presumably, that's what your type is) that tells you which union member you're using. Make life easier and have a std::variant instead, which does all this for you.

    That being said, you can std::memcpy/std::copy bits in and copy bits out, in say a uint64_t as long as they are a valid representation of the type you've chosen on your system. Just don't expect reinterpret_cast to be valid: it won't be.