Home > Blockchain >  Copying Byte Pattern For Floats Does Not Work
Copying Byte Pattern For Floats Does Not Work

Time:11-01

I am currently teaching myself c and learning all I can about memory. I found out that you can use a char pointer to copy the bit pattern of an int for example and store it in memory with casting:

#include <iostream>

using namespace std;

int main()
{

int x = 20;

char* cp = new char[sizeof(int)];

cp[0] = *((char*)&x);
cp[1] = *((char*)&x 1);
cp[2] = *((char*)&x 2);
cp[3] = *((char*)&x 3);

std::cout << (int)*cp; // returns 20; 


return 0;
}

the code above works, when I cast cp to a int so the compiler reads 4 bytes at a time, I get the correct number which is 20.

However changing it to a float:

#include <iostream>

using namespace std;

int main()
{

float x = 20;

char* cp = new char[sizeof(float)];

cp[0] = *((char*)&x);
cp[1] = *((char*)&x 1);
cp[2] = *((char*)&x 2);
cp[3] = *((char*)&x 3);

std::cout << (float)*cp; // returns 0.


return 0;
}

returns 0. Now I am a bit confused here. If I am copying every single byte, why is it still giving me a 0? If someone could help me out understanding this it would be very awesome.

CodePudding user response:

(int)*cp; first dereferences the pointer, returning a char value, that is now static-casted to integers. This will only work for the range char can store - 0 255 or -128 127 and requires a little-endian system.

It may seem that the way how to fix it would be *reinterpret_cast<float*>(cp); or *((float*)cp). Both are wrong and cause undefined behaviour because they break the strict aliasing rule.

The strict aliasing rule states that one can dereference a pointer to T only if there exists an object of type T at the memory location the pointer points to. With exception of char, std::byte, unsigned char. Meaning it is correct to inspect any type through cast to char, but one cannot simply interpret bunch of bytes as a random T.

The correct way to serialize and deserialize objects is:

#include <iostream>

using namespace std;

int main() {
    float x = 20.0f;

    // This is safe.
    char* cp1 = reinterpret_cast<char*>(&x);
    // Also safe because there is a float object at cp1.
    std::cout << *reinterpret_cast<float*>(cp1);

    // No need for dynamic allocation.
    char cp2[sizeof(float)];
    // Copy the individual bytes into a buffer.
    //  = Serialize the object.
    std::memcpy(cp2, &x, sizeof(x));

    // NOT SAFE, UNDEFINED BEHAVIOUR
    // There is no float object at cp2.
    std::cout << *reinterpret_cast<float*>(cp2);

    // Deserialization through copy
    float y;
    std::memcpy(&y, cp2, sizeof(y));
    // Safe
    std::cout << y;

    return 0;
}
  • Related