#pragma pack(N)
对齐模数N
对齐规则:一个变量的内存起始地址正好等于其长度的整数倍
补白padding的大小应该由补白区域的前一个变量类型和后一个变量类型共同决定
内存字节对齐、为什么要对齐
需要做到自然对齐的有:
- 基本的数据类型
- 结构体这样的复合结构
- 整个类实例(对象)
结构体:
结构体的总大小,必须是其内部最大成员的整数倍,不足的要补齐
将结构体也当做一个变量,其必然也需遵守对齐规则
其内部最大成员的长度被视为结构体变量对齐长度
即:一个结构体这样的复合结构的内存起始地址正好等于其内部最大成员长度的整数倍
对象:
整个类型实例所占的内存空间必须是类型中宽度最大的字段所占内存的整数倍
记:
一个变量的内存起始地址正好等于其长度的整数倍
结构体这样的复合结构的总大小,必须是其内部最大成员的整数倍,不足的要补齐
一个结构体这样的复合结构的内存起始地址正好等于其内部最大成员长度的整数倍
物理总线决定内存大小,内存大小和多字节指令决定了对齐规则
1.许多机器有处理单个字节指令,也有处理2、4、8字节指令。这种多字节处理就相当于把当前内存按多字节分块处理。例:内存16字节,8字节指令,则内存分两块,如果一个8字节数据存到了两个块内,则无法使用8字节指令一次读取到该数据。
2.要想使用安全且正确的使用多字节指令,就要保证数据在内存中也是多字节顺序存放。
3.通常的64位技术是相对32位而言的,这个位数指的是CPU GPRs(General-Purpose register通用寄存器)的数据宽度为64位,而32位的处理器的通用寄存器的数据宽度为32位,64位指令集就是运行64位数据的指令,也就是说一次可以运行64bit的数据
4.处理的寻址范围:要看处理器的地址总线的位数,而不是它的字长。!!!!!如Intel P4处理器字长为32位,地址总线也是32位。8086的数据总线为16为,地址总线为20位(则可寻址的内存空间为220=1MB)。新兴的64位处理器的数据总线为64位,地址总线大部分是32位。再看地址总线与寻址范围的关系,存储单元是以Byte为单位,N根地址总线能够访问2N个存储单元,于是有32为地址总线可访问232个存储单元,即4GB(232
÷
\div
÷ 1024
÷
\div
÷ 1024)
5.物理上的地址总线确定了内存大小是偶数,然后按照2中的说法,某个多字节在内存中顺序存放,那么理所当然,这个多字节变量的内存起始地址正好等于其长度的整数倍。
6.多个不同长度的多字节进行存放时,如果都能保证其各自的内存起始地址正好等于其长度的整数倍,这这种分配就符合我们所说的字节对齐,也就可以正确的使用多字节指令进行读取
#include <iostream>
#include <string>
#include <vector>
#include <memory.h>
#pragma pack()
typedef struct AA//1
{
char charA1;
}AA;
typedef struct BB//8
{
AA A6;
int int4;
}BB;
typedef struct CC//12
{
AA A6;
int int4;
short short2;
}CC;
int main()
{
std::cout<<sizeof(AA)<<" "<<sizeof(BB)<<" "<<sizeof(CC)<<std::endl;
return 0;
}
out:
1 8 12
#include <iostream>
#include <string>
#include <vector>
#include <memory.h>
#pragma pack()
typedef struct AA//6
{
char charA1;
short short2;
char charB1;
}AA;
typedef struct BB//12
{
AA A6;
int int4;
}BB;
typedef struct CC//16
{
AA A6;
int int4;
short short2;
}CC;
int main()
{
std::cout<<sizeof(AA)<<" "<<sizeof(BB)<<" "<<sizeof(CC)<<std::endl;
return 0;
}
#include <iostream>
#include <string>
#include <vector>
#include <memory.h>
#pragma pack()
//------------------------
union A {
double a;
char b;
};
union B {
int a;
char b;
};
union C {
float a;
char b;
};
union D {
short a;
char b;
};
//-------------------------
typedef struct a1
{
int id;
double weight;
}a1;
typedef struct a2
{
double weight;
int id;
}a2;
//--------------------------
typedef struct b1
{
int id;
char weight;
}b1;
typedef struct b2
{
char weight;
int id;
}b2;
//-------------------------
typedef struct c1
{
double id;
char weight;
}c1;
typedef struct c2
{
char weight;
double id;
}c2;
//--------------------------
typedef struct d1
{
short id;
char weight;
}d1;
typedef struct d2
{
char weight;
short id;
}d2;
typedef struct d3
{
char weight;
short id;
char icahr;
}d3;
//--------------------------
typedef struct e1
{
float id;
char weight;
}e1;
typedef struct e2
{
char weight;
float id;
}e2;
//--------------------------
typedef struct aa//8
{
d3 dd3;//6
short ss;
}AA;
typedef struct bb//6
{
char id; //
d1 d; //4
}BB;
typedef struct cc//12
{
d3 dd3;//6
int ss;
}CC;
typedef struct dd//16
{
CC dd3;
int ss;
}DD;
typedef struct ee//24
{
CC dd3;//12
double ss;//8
}EE;
typedef struct ff//20
{
CC dd3;//12
BB ss;//6
}FF;
int main()
{
std::cout<<sizeof(A)<<" "<<sizeof(B)<<" "<<sizeof(C)<<" "<<sizeof(D)<<std::endl;
std::cout<<sizeof(a1)<<" "<<sizeof(a2)<<std::endl;
std::cout<<sizeof(b1)<<" "<<sizeof(b2)<<std::endl;
std::cout<<sizeof(c1)<<" "<<sizeof(c2)<<std::endl;
std::cout<<sizeof(d1)<<" "<<sizeof(d2)<<" "<<sizeof(d3)<<std::endl;
std::cout<<sizeof(e1)<<" "<<sizeof(e2)<<std::endl;
std::cout<<sizeof(AA)<<" "<<sizeof(BB)<<" "<<sizeof(CC)<<" "<<sizeof(DD)<<" "<<sizeof(EE)<<" "<<sizeof(FF)<<std::endl;
return 0;
}
out:
#pragma pack()
8 4 4 2
16 16
8 8
16 16
4 4 6
8 8
8 6 12 16 24 20
#pragma pack(1)
8 4 4 2
12 12
5 5
9 9
3 3 4
5 5
6 4 8 12 16 12
#pragma pack(2)
8 4 4 2
12 12
6 6
10 10
4 4 6
6 6
8 6 10 14 18 16
#pragma pack(3)
main.cpp:5:15: warning: alignment must be a small power of two, not 3 [-Wpragmas]
5 | #pragma pack(3)
| ^
8 4 4 2
16 16
8 8
16 16
4 4 6
8 8
8 6 12 16 24 20
#pragma pack(4)
8 4 4 2
12 12
8 8
12 12
4 4 6
8 8
8 6 12 16 20 20