1. 字节对齐
字节对齐是字节按照一定规则在空间上排列。
现代计算机中内存空间的基础单元是字节(byte),从理论层面上讲,对于任何数据类型的变量的访问,都可以从任何地址开始。但是物理层面实现时,访问特定类型变量的时候经常需要在特定的内存地址访问,一般时以2,4或8的倍数的字节块来读写内存。
为什么要进行字节对齐?
一句话来说:以牺牲空间的方式来减少时间的消耗。
实际编程中,字节对齐的细节都是由编译器完成,但是需要知道变量是如何在内存中进行对齐的。
2. C/C++ 结构体
在C语言中,结构体可以用来存放一组不同类型的数据,结构体的定义形式为:
struct 结构体名
{
结构变量...
};
结构体变量定义:
struct 结构体名 变量名;
也可以在定义结构体的同时定义结构体变量:
struct Student
{
char name[24];
int student_id;
}stu1, stu2; // 定义结构体变量stu1, stu2
当只需要stu1, stu2
两个变量,后面不再需要使用结构体名定义其他变量,可以在定义时不给出结构体名
struct
{
char name[24];
int student_id;
}stu1, stu2; // 定义结构体变量stu1, stu2
C++中的结构体定义形式与C语言一样,只是在定义结构体变量时,不需要使用struct关键字
Student stu1, stu2;
typedef struct的区别
在C语言中使用typedef
定义结构名,在定义结构体变量时可以省去struct
关键字
typedef struct Student
{
char name[24];
int student_id;
} pStudent;// 别名
// 定义结构体对象
pStudent stu1; // 省去了struct
使用typedef struct之后,C/C++定义结构体对象代码相同。
3. 结构体对齐的公式
- 以
#pragma pack(x)
中x
和结构体中占用空间最大的成员做比较,取两者的最小值为n
- 以
n
值与结构体每个成员比较,得出结果列表为m[x]
- 根据每个成员的大小依次向内存中填充数据,要求填充成员的起始地址减去结构体起始地址的差值可以整除
m[x]
,如不能整除则向后移动,直到可以整除再填充成员到内存中 - 当全部成员填充完毕后所占用的字节数若不能整除
n
,则扩充内存至可以整除n
为止
#pragma pack(4)// 编译器将按照n个字节对齐
struct data
{
int a; // 4 bytes
char b; // 4 bytes
int c; // 4 bytes
short d; // 4bytes
}; // 16 bytes
#pragma pack() // 编译器将取消自定义字节对齐方式
struct data
{
int a; // 4 bytes
char b; // 2 bytes
short d; // 2bytes
int c; // 4 bytes
}; // 12 bytes
合理调整成员的位置,可以大大节省存储空间。但是需要在空间和可读性之间进行权衡。
4. 跨平台传输
由于不同平台对齐方式可能不同,可能导致同样的结构在不同的平台其大小可能不同,导致发送的数据可能出现错乱,引起严重问题。
为了不同处理器之间能够正确处理结构体,有两种可选的处理方法:
- 1字节对齐
- 自己对结构 进行字节填充
可以使用伪指令#pragma pack(n)
来使得结构之间按照一字节对齐
#pragma pack(1)
typedef struct
{
int a;
char b;
short d;
int c;
} DATA;
#pragma pack()
int main()
{
DATA data1 = {4, 'c', 2, 6};
DATA data2 = {};
memcpy(&data2, &data1, sizeof(DATA));
cout << "sizeof(DATA) > : " << sizeof(DATA) << endl;
cout << "data: " << data2.a << " " << data2.b << " " << data2.c << " " << data2.d << endl;
return 0;
}
// sizeof(DATA) > : 11
// data: 4 c 6 2
对于单个结构体,如下的方法,可使其按一字节对齐
typedef struct
{
int a;
char b;
short d;
int c;
} __attribute__ ((packed)) DATA;
__attribute__ ((packed))
:取消结构在编译过程中的优化对齐,即可以认为是一字节对齐
人为填充方式
typedef struct
{
int a;
char b;
char reserve[3]; // 填充
int c;
short d;
char reserve1[2]; // 填充
} DATA;