- 类型双关指的是,C绕过类型系统的一种方式,C是强类型语言,不会把所有东西都设置为auto(可以,但不推荐)
- C++中类型在一定程度上由编译器强制限定,但你可以直接访问内存
- 本章节实例会访问某个int数值的内存,并把它当做双精度数来处理(轻易绕过类型系统)
- 假设有一个类(基本类型结构体),我们想把它写成字节流,它没有其他指针指向它,那么我们可以直接解释整个结构体、类、或者其他东西,这里会视为字节数组:只要我们知道任何大小,就可以直接访问数据
转换#
#ifdef LY_EP66
#include <iostream>
int main()
{
//小端法,低字节的数据存储在内存的低地址处,
// 高字节的数据存储在内存的高地址处
//Ox00000032
int a = 50;// 32 00 00 00
//隐式转换,a隐式转换成了double类型
//相当于 double value =(double)a
//Ox404900000000000000,double数值50
//的16进制表示为0x4049000000000000
double value = a;// 00 00 00 00 00 00 49 40
std::cout << value << std::endl;
std::cin.get();
}
#endif转换后内存中的数值变了
类型双关-不同方式读取同一内存#
#ifdef LY_EP66
#include <iostream>
int main()
{
int a = 50;
//把a(内存处)的内存以double类型的方式进行访问
//将整型进行类型双关变成双精度型
//* 操作符会尝试从该地址开始,一口气往后读 8 个字节,这里是
//32 00 00 00 cc cc cc cc (小端法)
double value = *(double*)&a;
std::cout << a << std::endl;
std::cout << value << std::endl;
//不想创建全新变量,只是想把这个整数当成双精度数来访问,
//那么可以在这个双精度数后面加&,这样就能引用他
//强行让 value1 成为 &a 处那块 8 字节内存的别名。通过
// value1 修改数据会直接破坏 a 及其相邻内存。
double& value1 = *(double*)&a;
//这里会把8个字节(a和a后面的4个字节)都写入0
value1 = 0;
std::cin.get();
}
#endif
value在新的内存地址上:


跳到下一步把value1改了

类型双关-不同方式解释内存#
#ifdef LY_EP66
#include <iostream>
struct Entity
{
int x, y;
int* GetPosition()
{
//替换了复制的写法
/*int* array = new int[2];
array[0] = x;
array[1] = y;*/
return &x;
}
};
struct EmptyStr
{
};
int main()
{
//聚合初始化(Aggregate Initialization)机制
Entity e = { 5,8 };//05 00 00 00 08 00 00 00
Entity e1 = { 5 };//05 00 00 00 00 00 00 00
Entity e2 = {};//00 00 00 00 00 00 00 00
EmptyStr es = {};//00 空结构体但是也占用了一个字节
int x1 = e.x;
//指针形式的原始地址
//这是一个:指向一个整数的指针
int* position = (int*)&e;
std::cout << position[0] << "," << position[1] << std::endl;
int y1 = e.y;
// 1. (char*)&e:
// 将 e 的首地址强制看作 char* 指针。
// 意义:因为 char 占用 1 字节,这能让指针的“步长”变为 1 字节,方便我们进行精确的地址加减。
// 2. + 4:
// 在 char* 的基础上移动 4 个单位。
// 意义:因为步长是 1,所以这里实际上是向后偏移了 4 个字节,跳过了第一个成员 x。
// 3. (int*):
// 将偏移后的新地址再次强制转换回 int*。
// 意义:告诉编译器:“从这个位置开始,请用 int 的滤镜来看待这块内存”。
// 4. *:
// 对 int* 进行解引用。
// 意义:从当前偏移后的地址起,一口气读取 4 个字节,并将其作为整数赋值给 y。
int y = *(int*)((char*)&e + 4);
std::cout << y << std::endl;
//得到一个有两个元素的实际整型数组
int* position1 = e.GetPosition();
std::cout << position1[0] << std::endl;
std::cout << position1[1] << std::endl;
std::cin.get();
}
#endif- 通过重新解释内存,实现了“类型转换”
- 把那个类型当做指针,然后将其转换为另一个指针,之后如有必要 解引用并处理它就行