结构体在内存的表现形式
结构体
1.我们在之前讲过结构体struct 都知道struct 可以存放很多不同数据类型的数据
2.这必将导致一个问题出现
3.我们的结构体需要内存对齐
4.如果不对齐 会导致内存排列很错乱(除非一些特殊需求 比如:我们在逆向找数据的时候 变得有些困难 不能一眼看出是什么类型的数据)
5.好 这里我们给大家举个例子看一下
举例
1.我们在之前讲过 默认是8字节
#include <stdio.h>
#include "windows.h"
typedef struct INFO
{
char flag;
int id;
float fd;
}INFO;
INFO info = {'H',1001,666.66f};
int main()
{
printf("%c-%d-%f\n", info.flag, info.id, info.fd);
printf("Hello Heart");
system("pause");
return 0;
}
我们编译一下 用xdbg看一下在内存中的对齐是怎么样子的
2.我们附加XDBG
3.ctrl+G 输入_main 来到main函数
4.找到这个全局变量地址
5.观察结构体内存 注意:在xdbg这个内存窗口地址是 右到左 地址在增加 不是左到右 所以你会看到48在右边
6.这里我们为了好看 双击这个0049A000地址 可以看到偏移量
7.这个偏移量我们再内存对齐的时候已经给大家说过了
8.此时我们发现数据很整齐 这使得我们观察数据变得尤其的简单
9.有经验的同学也能立马看出这些数据的类型是什么 起码基本上不会差太多
举例2
1.经过我们上面的发现 内存对齐是有优势的
2.但是上面也说过 我们可以改变内存对齐 来使内存存放不规律
3.好现在 我们改下内存对齐看看此时在内存的表现是怎么样的
4.只需要加上 #pragma pack(push,1) #pragma pack(pop)就行
#include <stdio.h>
#include "windows.h"
#pragma pack(push,1)
typedef struct INFO
{
char flag;
int id;
float fd;
}INFO;
#pragma pack(pop)
INFO info = {'H',1001,666.66f};
int main()
{
printf("%c-%d-%f\n", info.flag, info.id, info.fd);
printf("Hello Heart");
system("pause");
return 0;
}
5.我们这里修改的是1字节对对齐
6.重复上述举例1观察下内存
7.你会惊奇的发现这些值是什么啊!怎么看不懂!
8.我们一个一个的看 每个数据都是紧密的挨着一起的 这会使得我们观察数据很费劲
通过指针+偏移来获取结构体里面的值
1.这里我们暂时吧内存对齐设置为默认8
#include <stdio.h>
#include "windows.h"
#pragma pack(push,1)
typedef struct INFO
{
char flag;
int id;
float fd;
}INFO;
#pragma pack(pop)
INFO info = {'H',1001,666.66f};
int main()
{
char c = *((char*)(&info));
printf("c=%c\n", c);
int id = *((int*)((DWORD)(&info) + offsetof(INFO, id)));
printf("id=%d\n", id);
printf("%c-%d-%f\n", info.flag, info.id, info.fd);
printf("Hello Heart");
system("pause");
return 0;
}
2.就算我们把对齐数设置为1 也能正确获取 因为我们借助了offsetof函数
#include <stdio.h>
#include "windows.h"
typedef struct INFO
{
char flag;
int id;
float fd;
}INFO;
INFO info = {'H',1001,666.66f};
int main()
{
char c = *((char*)(&info));
printf("c=%c\n", c);
int id = *((int*)((DWORD)(&info) + offsetof(INFO, id)));
printf("id=%d\n", id);
printf("%c-%d-%f\n", info.flag, info.id, info.fd);
printf("Hello Heart");
system("pause");
return 0;
}
3.效果是一样的
4.但是实际上我们再找数据的时候 不知道结构体的类型长什么样的 因为我们的宏函数offsetof是需要知道变量名和结构体类型的
5.所以实际我们再数据中找的偏移就是这个函数算出来的偏移
总结
1.结构体的成员变量在结构体中排列的方式依据于对齐方式
2.结构体变量的地址就是结构体的首地址 也是我们结构体第一个成员变量的地址
3.我们的偏移量是依据与结构体首地址开始算的
4.设置内存对齐可以让结构体在内存中的排列方式变得不易于找数据
迪大交流群:285530835