0

I want to convert a hexadecimal string that is the memory dump of a float to float. I tried this code:

#include <iostream>
#include <string>

using namespace std;

int main() {
    std::string hexString = "0x3f9d70a4";
    float floatValue = std::stof(hexString, nullptr);
    cout << floatValue;
}

But this program outputs 1.06728e+09 instead of 1.23

Any pointers on how to convert it appropriately in C++

vijayst
  • 20,359
  • 18
  • 69
  • 113
  • 1
    It seems that you obtained that value via type punning, have you considered [`std::hexfloat`](https://en.cppreference.com/w/cpp/io/manip/fixed) instead? Otherwise, since C++20, there's [`std::bit_cast`](https://en.cppreference.com/w/cpp/numeric/bit_cast), but not from a `std::string`. – Bob__ Jul 14 '23 at 15:30
  • 1
    Convert to the corresponding `uint32_t` and `memcpy` or `std::bit_cast` into a `float`. – Aconcagua Jul 14 '23 at 15:31
  • Side note: About [`using namespace std`](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) – and even worse, this code intermixes qualified and non-qualified… – Aconcagua Jul 14 '23 at 15:33
  • Not posting this as an answer because it's not very c++, but depending on how much you care about that, `sscanf(hexString.c_str(), "%x", &floatValue);` is all you need, assuming you remove the `0x` prefix from the string – Douglas B Jul 14 '23 at 15:33
  • @DouglasB This causes undefined behaviour! – Aconcagua Jul 14 '23 at 15:34
  • @Aconcagua interesting, Im not sure I see where, Im assuming it's from using %x here, but if not, I would appreciate if you could point me to the rule Im breaking. Not doubting that I am, but I get no warnings from the compiler even with `-Wall` and it works fine for me so I am curious – Douglas B Jul 14 '23 at 15:39
  • Minor point: formally, output from a program must end with a newline character, so that output should be `std::cout << floatValue << '\n';`. In reality, pretty much every system you'll encounter does just what you expect if you leave out the newline. But, in general, you need newlines to separate lines of output, and there's no benefit in leaving the newline off of the last one. – Pete Becker Jul 14 '23 at 15:41
  • @DouglasB The type of the variable to read into must match the format specifier, otherwise undefined behaviour. `%x` expects `unsigned int`, not `float`. – Aconcagua Jul 14 '23 at 15:45
  • 1
    @DouglasB: For %x: "The corresponding argument shall be a pointer to unsigned integer." (C99, §7.19.6.2). – Jerry Coffin Jul 14 '23 at 15:47
  • @Aconcagua Thank you for confirming that for me. I guess I've been treating `%x` as more of a 'raw/hex bytes' thing than an unsigned int, seeing as there's `%u` for unsigned ints. Im curious then if you know offhand: If I were to create another variable which is an unsigned int, `tmp` and read into that with `%x`, is it legal to then reinterpret that memory as a float such as `floatValue = *(float*)&tmp;` (assuming you know they're the same size)? This again gives the correct value in my case, but I could also see that being UB. – Douglas B Jul 14 '23 at 16:03
  • @DouglasB That's just as much undefined behaviour, and type-punning via a union would be as well (in C++ – while legal in C). – Aconcagua Jul 14 '23 at 16:05
  • 1
    @Aconcagua: Not so. §[cstdio.syn]/1: "The contents and meaning of the header are the same as the C standard library header ." The only part that might be open to the slightest question is whether I cited the proper edition of the C standard (e.g., C99 for C++11, but C18 for C++23). – Jerry Coffin Jul 14 '23 at 16:27

0 Answers0