滴水逆向 02-05 字节对齐_结构体数组
结构体对齐
观察到一个现象:
1 | struct S1 { |
-
为什么要有数据对齐?
本质:效率还是空间,二选一的结果 -
选择空间还是效率?
#pragma pack的基本用法:1
2
3
4
5
6
7
8
9
10
11
//结构体。。。
struct test {
int a;
__int64 b;
char c;
}对齐参数:n 为字节对齐数,其取值为 1、2、4、8,默认为 8。整个结构体的占用内存大小也应当是 n 的整数倍。
如果这个值比结构体成员的 sizeof 值小,那么该成员的偏移量应该以此值为准。也就是说,结构体成员的偏移量需要取二者之间的最小值。
各种对齐参数下数据的存储形式:

1字节对齐是最省空间的,看一下他在内存中是怎么存的:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct test {
int a;
__int64 b;
char c;
}
int main(int argc, char* argv[]) {
test t;
t.a = 1;
t.b = 2;
t.c = 3;
printf("%d\n", sizeof(test)); //13
return 0;
}
-
对齐原则
原则一:数据成员对齐规则——结构的数据成员,第一个数据成员放在 offset 为 0 的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如 int 在 32 位机为 4 字节,则要从 4 的整数倍地址开始存储)。
原则二:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。
原则三:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储(struct a 里存有 struct b,b 里有 char、int、double 等元素,那 b 应该从 8 的整数倍开始存储)。
原则四:对齐参数如果比结构体成员的 sizeof 值小,该成员的偏移量应该以此值为准。也就是说,结构体成员的偏移量应该取二者的最小值。每个成员的 offset 满足自己的对齐要求即可。
以上四个原则都是在默认对齐参数是 8,并且成员都是 char, short, int, float, double, __int64 这种的情况下的 -
三个案例(对齐参数为默认值8):
1
2
3
4struct Test {
char a;
int b;
};
1
2
3
4
5struct Test {
int a;
__int64 b;
char c;
};
1
2
3
4
5
6struct Test {
int a;
__int64 b;
char c;
char d;
};
-
建议:定义的时候按照数据类型从小到大的顺序,这样可以尽可能避免空间浪费
typedef 和结构体数组就不记了,都是基础正向的
课后作业
正向代码部分略
- 分析下面结构体的内存分配

