其实主要是想说明编译器太坑了(以下都是在32位环境下)
刚开始使用的是vs2010,一个int a ,缓冲区都要增大0xC
我人都傻了,两个int 增大0x18, char c[12] 增大0x20
一个double 直接占用0x10 ,值放在0x4-0xC 形成 4 8 4
疯狂的浪费空间,我也不晓得原因,先做个记录帖,以后再翻案吧
然后再装一个vc6,就完全符合我的预期
局部变量(定义局部变量在缓冲区中)
char a; 四个字节
short a;四个字节
int a; 四个字节
double a;八个字节
char a[3];char a[4] ;四个字节
总结1:局部变量会根据CPU宽度进行对齐
注意 连续两个char 也分别占四字节,总共占8字节,原因,局部变量使用频率较高,一般数量不多,使用空间换时间,CPU执行取存四个字节最快
例如:char还要有无符号扩展才能传,就麻烦,四字节就直接传,将局部变量设置为0x00 00 00 char 这样只要mov al,XXX或者mov byte ptr [],xxx 减少了一条命令
但是如果在结构体或者字符串中时,就会进行合并
#pragma pack(n) vc6默认pragma pack(8) (这里没看官方文档,听海哥讲的,不确定)
规则是 min(n,类型),并且最后长度为n的整数倍,n只能取2,4,8,16(不确定)写6警告但是对齐不以6
写的过大,编译器会将其变小到最大基础变量长度,(自己遍历一遍找个最大基础定义数据类型)
#pragma pack(8)
struct {
int a; //min(4,8) 4 4 a a a a
char b: //min(1,8) 1 4 b ? //这个?是short补的
short c; //min(2,8) 2 4 c c ?? 注意short要以2对齐,前面就5个所以补一个
double d: //min(8,8) 8 4 1 ? 2 8 结束
};
#pragma pack()
a a a a b ? c c
d d d d d d d d
共计16字节
#pragma pack(1)
struct { min(类型,n) 小的数 实际占的空间
int a; //min(4,1) 1 4
char b: //min(1,1) 1 4 1
short c; //min(2,1) 1 4 1 2
double d: //min(8,1) 1 4 1 2 8 结束
};
#pragma pack()
4 1 2 8
共计15字节
waring :expected pragma parameter to be '1', '2', '4', '8', or '16' 编译器警告
继续提升难度
struct test
{
char a[6];
};
struct test2
{
char a;
int b;
};
struct ttest
{
char a;
struct test tt;
char b;
int c;
};
struct ttest2
{
char a;
struct test2 tt;
char b;
int c;
};
根据内存 ttest
a tt.a[0] tt.a[1] tt.a[2]
tt.a[3] tt.a[4] tt.a[5] b
c c c c
12个字节
根据内存 ttest2
a ? ? ?
tt.a ? ? ?
tt.b tt.b tt.b tt.b
b ? ? ?
c c c c
20字节,好难啊
为啥ttest 合并了数组 ttest2没有合并呢
猜测 test 和 test2的字符宽度不一样
test的字符宽度为1
即 ttest
char a
char tt[6]
char b
int c
test2的字符宽度为4
即ttest2
char a
int tt[2]
char b
int c
解决,感觉没毛病
总结2:
结构体,如果不加#pragma pack() 根据最长数据类型对齐(数组算单个元素长度,结构体里结构体也是这样计算)
如果加了就会根据两者小的那个进行数据类型对齐。
1.即遍历结构体 get 最长数据类型长度
2.最长数据类型长度和 #pragma pack(n) 取小值
3.根据小值对齐
附:结构体里结构体就要看内部结构体的数据宽度而形成的类数组,
个人总结:不确定对错,目前没出问题
完事,因为编译器选择,基础规则也有所变化,留意这个坑点。