目录

一、为什么要内存对齐

二、基本变量类型所占大小

三、影响内存对齐的情况

四、先说结论(重要)

五、举亿点例子(以下内容均实际运行过,质量保证)

例1:研究结构体最后一个成员内存对齐问题1

例2:研究结构体最后一个成员内存对齐问题2

例3: 研究数组的内存对齐

例4:枚举 & 研究数组之间的内存对齐

例5:结构体嵌套1

例6:结构体嵌套2

例7:__attribute__((packed))

例8:#pragma pack (n)

写在前面:本次实验所用到的环境:Windows 10 Visual Studio(64 位)、Ubuntu 18.04 x86_64-linux-gnu(64 位)!!

一、为什么要内存对齐

简单来说,就是方便计算机去读写数据。

对齐的地址一般都是 n(n = 2、4、8)的倍数。

(1). 1 个字节的变量,例如 char 类型的变量,放在任意地址的位置上;

(2). 2 个字节的变量,例如 short 类型的变量,放在 2 的整数倍的地址上;

(3). 4 个字节的变量,例如 float、int 类型的变量,放在 4 的整数倍地址上;

(4). 8 个字节的变量,例如 long long、double 类型的变量,放在 8 的整数倍地址上;

二、基本变量类型所占大小

注:蓝色标记部分特别注意!!

数据类型ILP32(32位Linux系统)LP64(大部分64位Linux系统)LLP64(64位Windows系统)
char1 字节1 字节1 字节
short2 字节2 字节2 字节
int4 字节4 字节4 字节
float4 字节4 字节4 字节
long4 字节8 字节4 字节
double8 字节8 字节8 字节
long long8 字节8 字节8 字节
指针 point4 字节8 字节8 字节
枚举 enum4 字节4 字节4 字节
联合体 union取 union 中最大一个变量类型大小取 union 中最大一个变量类型大小取 union 中最大一个变量类型大小

ILP32 指 int,long、point 是 32 位。

LP64 指 long、point 是 64 位。

LLP64 指 long long、point 是 64 位。

三、影响内存对齐的情况

1、变量排列顺序。

2、__attribute__((packed))取消变量对齐,按照实际占用字节数对齐(就是让变量之间排列紧密,不留缝隙)。(gcc才支持)详见例7。

3、#pragma pack (n):让变量强制按照 n 的倍数进行对齐,并会影响到结构体结尾地址的补齐(详见四的通常情况下关于结尾地址补齐的描述)。详见例8。

四、先说结论(重要)

下面的结论均为系统默认对齐规则下进行的:

通常情况:我总结的规律如下:结构体中间:各结构体的起始地址按照各个类型变量默认规则进行摆放,但除了 char 类型变量(详见一),char 类型变量一般遵循 2 的倍数地址开始存储。详见例2。结构体最后(重要)视结构体中最大类型是哪一个,如果是像 int 类型那样是 4 个字节的,并且结构体的结尾地址不满足 4 的倍数的话,向离最近的 4 的倍数地址补齐;如果是像 double 类型那样是 8 个字节的,并且结构体的结尾地址不满足 8 的倍数的话,向离最近的 8 的倍数地址补齐;以此类推。。。。

结构体嵌套:子结构体的成员变量起始地址要视子结构体中最大变量类型决定,比如 struct a 含有 struct b,b 里有 char,int,double 等元素,那 b 应该从 8 的整数倍开始存储。详见例5、例6。

含数组成员:比如 char a[5],它的对齐方式和连续写 5个 char 类型变量是一样的,也就是说它还是按一个字节对齐。详见例1、例2、例3、例4、例5。

含联合体(union)成员:取联合体中最大类型的整数倍地址开始存储。详见例5。

个人总结能力有限,还是观看例子更容易理解:

五、举亿点例子(以下内容均实际运行过,质量保证)

没有特别标注就是 64 位!!

例1:研究结构体最后一个成员内存对齐问题1

struct stu1 {char a[18];double b;char c;int d;short e;};

Windows 10:48 字节Ubuntu 18.04:48 字节

例2:研究结构体最后一个成员内存对齐问题2

struct stu1 {char a[18];int b[3];short c;char d;int e;short f;};

Windows 10:44 字节Ubuntu 18.04:44 字节

例3: 研究数组的内存对齐

struct stu1 {int a;char b[8];float c;short d;};

Windows 10:20 字节Ubuntu 18.04:20 字节

例4:枚举 & 研究数组之间的内存对齐

enum DAY {MON = 1, TUE, WED, THU, FRI, SAT, SUN};struct stu1 {char a[5];char b[3];enum DAY day;int *c;short d;int e;};

Windows 10:32 字节Windows 10(32位):24 字节 Ubuntu 18.04:32 字节

64位:

32位:

例5:结构体嵌套1

struct stu2 {char x;int y;double z;char v[6];};struct stu1 {union u1 {int a1;char a2[5];}a;struct stu2 b;int c;};

Windows 10:40 字节Ubuntu 18.04:40 字节

例6:结构体嵌套2

struct stu2 {char x;int y;double z;char v[6];};struct stu1 {char a;struct stu2 b;int c;};

Windows 10:40 字节Ubuntu 18.04:40 字节

例7:__attribute__((packed))

由于 VS 和 VScode均不支持 __attribute__((packed)),于是只使用 gcc 编译。

struct __attribute__((packed)) stu1 {// 取消内存对齐char a;long b;short c;float d;int e;};

Ubuntu 18.04:19字节

例8:#pragma pack (n)

#pragma pack (2)// 强制以 2 的倍数进行对齐struct stu1 {short a;int b;long c;char d;};#pragma pack ()// 取消强制对齐,恢复系统默认对齐

Windows 10:12 字节Ubuntu 18.04:16 字节

正常情况:

Windows 10:

Ubuntu 18.04: