Ad
  • Default User Avatar

    Good point; it's an easily missable diference between C and C++. :)

    It looks like most major C++ compilers actually do allow union-based type punning as an extension, even though it isn't strictly required.
    GCC explicitly allows it even when -fstrict-aliasing is enabled, as long as you don't access union elements via a pointer.

    I had trouble finding an official reference on how Clang behaves, but I played around in Compiler Explorer for a bit and both GCC and Clang handled union-based punning gracefully even on -O3. Neither issued any warnings with -Wall -Wextra -Wpedantic enabled.

    So it's probably fine to type-pun with unions on the major compilers, but I imagine things could get """fun""" quickly in lesser-used environments.

  • Default User Avatar

    interestingly, union type punning is undefined behavior in C++ but not in C

  • Default User Avatar

    This solution is pretty slick, but it unfortunately invokes undefined behavior in the two pointer casts due to C++'s type aliasing rules. Essentially, referring to a value of type T through a pointer of a different type U* is undefined behavior unless U is the signed/unsigned equivalent of T; or at least one type is char, unsigned char, or std::byte.
    Many compilers are cautious and will try not to screw you over for doing this, but it can result in your code breaking in unpredictable ways on different compilers or different optimization levels.

    To my knowledge, the only safe way to treat a float as a uint32_t in C++17 is to use char* (or similar) pointers to copy bytes from the float value into a separate uint32_t value, like how std::memcpy does. (Trying to do this via a union type is also undefined behavior, so you unfortunately are required to copy the bytes into a separate buffer object.)

    C++20 has std::bit_cast, which is designed exactly for this purpose, but Codewars unfortunately does not support C++20 yet. :(