c++memorybinarycoutmemcpy

Why does memcpy result in an unexpected value?


#include <iostream>
#include <cstring>
#include <bitset>

using namespace std;

int main()
{
    double tx = 0xFFFF0000FFFF0000;
    uint64_t tx1 = 0;
    
    static_assert(sizeof(double) == sizeof(uint64_t));
    memcpy(&tx1, &tx, sizeof(double));
    bitset<64> b1(tx1);
    
    cout << b1 << endl;
    
    return 0;
}

As I expected, the tx1 should be 0xFFFF0000FFFF0000

but b1 yields 0x43EFFFE0001FFFE0.

I'd like to know how to make b1 equal to 0xFFFF0000FFFF0000.


Solution

  • 0xFFFF0000FFFF0000 is some integer value, but the important thing to note is that a 64 bit wide double can only represent integers up to 53 bits. After that you just get the closest approximation.

    When that happens, you now have some double object of a value close to but not exactly 0xFFFF0000FFFF0000.

    You then std::memcpy the double representation back into an integer but since the double is no longer 0xFFFF0000FFFF0000 then neither will your integer.

    Another thing to note is that floating point types and integer types have different binary representations. 42 in a double does not have the same binary representation as 42 does in uint64_t. This means that; no matter what, you'll never get the same bit pattern back out of the operation.


    One thing you can do is use memcpy both ways.

    uint64_t start = 0xFFFF0000FFFF0000;
    double tx;
    uint64_t tx1;
    memcpy(&tx, &start, sizeof(start));
    // now `tx` is some value but it has the binary representation of 0xFFFF0000FFFF0000
    memcpy(&tx1, &tx, sizeof(tx));
    // now tx1 has the binary representation of 0xFFFF0000FFFF0000 since the bits never get changed