我目前正在自学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。
但是把它改成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;
}
返回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;
}