复制浮点数的字节模式不起作用
Copying Byte Pattern For Floats Does Not Work
我目前正在自学 C++ 并尽我所能学习有关内存的知识。我发现您可以使用 char 指针来复制 int 的位模式,并通过转换将其存储在内存中:
#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;
}
上面的代码有效,当我将 cp 转换为 int 以便编译器一次读取 4 个字节时,我得到正确的数字 20。
但是将其更改为浮点数:
#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.现在我在这里有点困惑。如果我复制每个字节,为什么它仍然给我一个 0?如果有人能帮助我理解这一点,那就太棒了。
(int)*cp;
首先取消对指针的引用,返回一个 char
值,该值现在被静态转换为整数。这仅适用于 char
可以存储的范围 - 0 255
或 -128 127
并且需要小端系统。
似乎修复它的方法是 *reinterpret_cast<float*>(cp);
或 *((float*)cp)
。两者都是错误的,并且会导致未定义的行为,因为它们违反了严格的别名规则。
严格的别名规则指出,只有在指针指向的内存位置存在 T
类型的对象时,才能取消引用指向 T
的指针。 char
、std::byte
、unsigned char
除外。这意味着通过转换为 char
来检查任何类型都是正确的,但是不能简单地将一堆字节解释为随机的 T
.
序列化和反序列化对象的正确方法是:
#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;
}
我目前正在自学 C++ 并尽我所能学习有关内存的知识。我发现您可以使用 char 指针来复制 int 的位模式,并通过转换将其存储在内存中:
#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;
}
上面的代码有效,当我将 cp 转换为 int 以便编译器一次读取 4 个字节时,我得到正确的数字 20。
但是将其更改为浮点数:
#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.现在我在这里有点困惑。如果我复制每个字节,为什么它仍然给我一个 0?如果有人能帮助我理解这一点,那就太棒了。
(int)*cp;
首先取消对指针的引用,返回一个 char
值,该值现在被静态转换为整数。这仅适用于 char
可以存储的范围 - 0 255
或 -128 127
并且需要小端系统。
似乎修复它的方法是 *reinterpret_cast<float*>(cp);
或 *((float*)cp)
。两者都是错误的,并且会导致未定义的行为,因为它们违反了严格的别名规则。
严格的别名规则指出,只有在指针指向的内存位置存在 T
类型的对象时,才能取消引用指向 T
的指针。 char
、std::byte
、unsigned char
除外。这意味着通过转换为 char
来检查任何类型都是正确的,但是不能简单地将一堆字节解释为随机的 T
.
序列化和反序列化对象的正确方法是:
#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;
}