一. 类型双关
类型双关用来在C++中绕过类型系统。是强制类型语言。当我们创建变量时必须声明类型等等。**但我们可以直接访问内存。**所以实际上内存双关就是我们对某个类型的内存进行另一种类型的解释,把它解释为任意数据类型,类型双关实际上就是C语言中的指针类型转换操作,利用不同类型的指针对内存进行操作
1.
#include<iostream>
#include<vector>
int main()
{
int a = 50;
double value = *(double*)&a;
std::cout << value << std::endl;
std::cin.get();
}
double& value = *(double*)&a;
value = 0.0;
取a的地址然后把它转换成double指针,再解引用,此时解引用的指针是double类型,它会从起始地址向后查询八个字节解释出来再赋入value变量。这就是类型双关,这样访问这个doule值是错误的,因为原始int只占了四个字节,但实际上我们访问了并不属于a变量的后四个字节。
2.
如果结构体是空则至少要有一个字节,用来寻址,如果结构体里面有数据,那么结构体大小就是数据大小。
如下,将Entity结构体利用一个原始数组int* position接收 : 让它等于e的地址,然后将e的地址转换成int*,然后打印出来。因为我们将它们转换成了数组,所以像访问数组那样访问它们。e包含了int数组的开始地址,也就是包含了指向int的指针。
#include<iostream>
struct Entity
{
int x, y;
};
int main()
{
Entity e = { 5,8 };
int* position = (int*)&e;
std::cout << position[0] << "," << position[1] << std::endl;
std::cin.get();
}
二.联合体union
联合体内部成员变量公用同一个内存。
一个结构体声明了4个浮点数,占16个字节内存。
一个联合体声明声明4个浮点数,这四个变量占用相同内存,大小是4个字节。
可以给联合体添加静态函数或者普通函数或者方法等等,但不能使用虚方法。
2.1
使用联合体是和类型双关紧密相关的,当想给 一个变量取两个不同的名字时非常有用。
通常匿名使用Union,匿名union不能含有成员函数。
如下代码。
#include<iostream>
int main()
{
// 定义了一个结构体,这个就是结构体,和union无关
struct Union
{
// 这里面用union括起来,说明里面的float a 和int b占用相同的内存。否则他们俩就是占用不同的内存
union
{
float a;
int b;
};
};
Union u;
u.a = 2.0f;
std::cout << u.a << "," << u.b << std::endl;
std::cin.get();
}
上述结果a,b共享内存,为a赋值相当于同时为a,b赋值,但设置类型不一,在输出时a输出正常结果,而b无法解释float类型,打印出错
2.2.实例2
使用类型双关(指针类型重解释)
如下代码有Vector2,Vector4两个结构体,还有一个函数PrintVector2,参数类型是Vector2。
通过观察可以发现实际上Vector4就是由两个Vecotr2组成的。所以我访问Vecotr4的时候为了提高访问效率,可以一次访问两个数,即把他们分成x,y和z,w两组来访问,每一组都可以看成是一个Vecotr2的类型。
#include<iostream>
struct Vector2
{
float x, y;
};
struct Vector4
{
float x, y, z, w;
Vector2& GetA()
{
return *(Vector2*)&x;
}
Vector2& GetB()
{
return *(Vector2*)&z;
}
};
void PrintVector2(const Vector2& vector)
{
std::cout << vector.x << "," << vector.y << std::endl;
}
int main()
{
std::cin.get();
}
使用联合体union
另外一个方法是在Vector4中定义一个union联合体结构,然后它包括Vector原来的数据float x,y,z,w。
由于我们目的是让我们的数据float x, y, z, w能转换为两个Vecotr的格式进行访问,所以还需要在联合体中定义新的数据Vecotr a, b。
注意:由于union里面的变量会只会占有同一个内存,所以不能直接把float x, y, z, w和Vecotr a, b写在union里面,这样就变成6个变量共享内存了。我们想要的是两个变量共享内存,所以使用结构体struct把他们包起来。注意这里的结构体是匿名结构体,也就是直接写struct,而没有名字struct A之类的。因为这里就是想组织一下数据结构而已。
#include<iostream>
struct Vector2
{
float x, y;
};
struct Vector4
{
union
{
// 若写成struct A,即给结构体取了名字A,则会报错。因为他这里应该是匿名的
// 如果它是匿名的,它只是一种数据结构,没有添加任何东西。
// 这里使用struct组织成结构体的好处是它将4个变量转换成1个单元,这就是union所期望做的事。
struct
{
// 真正的变量在这里
float x, y, z, w;
};
// 再建立一个结构体,这样这个结构体里面的变量和上面的结构体里面的变量就共享内存了
struct
{
Vector2 a, b;
};
};
};
void PrintVector2(const Vector2& vector)
{
std::cout << vector.x << "," << vector.y << std::endl;
}