内存对齐
来源:互联网 发布:win10摄像头拍照软件 编辑:程序博客网 时间:2024/06/06 12:42
内存对齐
内存地址对齐,是一种在计算机内存中排列数据(表现为变量的地址)、访问数据(表现为CPU读取数据)的一种方式,包含了两种相互独立又相互关联的部分:基本数据对齐和结构体数据对齐 。
存在内存对齐原因:
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;
某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在⾃然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存
问;而对齐的内存访问仅需要一次访问。
1、基本数据对齐
在X86,32位系统下基于Microsoft、Borland和GNU的编译器,有如下数据对齐规则:
a、一个char(占用1-byte)变量以1-byte对齐。
b、一个short(占用2-byte)变量以2-byte对齐。
c、一个int(占用4-byte)变量以4-byte对齐。
d、一个long(占用4-byte)变量以4-byte对齐。
e、一个float(占用4-byte)变量以4-byte对齐。
f、一个double(占用8-byte)变量以8-byte对齐。
g、一个long double(占用12-byte)变量以4-byte对齐。
h、任何pointer(占用4-byte)变量以4-byte对齐。
64位系统下:
a、一个long(占用8-byte)变量以8-byte对齐。
b、一个double(占用8-byte)变量以8-byte对齐。
c、一个long double(占用16-byte)变量以16-byte对齐。
d、任何pointer(占用8-byte)变量以8-byte对齐。
2、结构体数据对齐
结构体数据对齐,是指结构体内的各个数据对齐。在结构体中的第一个成员的首地址等于整个结构体的变量的首地址,而后的成员的地址随着它声明的顺序和实际占用的字节数递增。为了总的结构体大小对齐,会在结构体中插入一些没有实际意思的字符来填充(padding)结构体。
在结构体中,成员数据对齐满足以下规则:
在X86,32位系统下基于Microsoft、Borland和GNU的编译器,有如下数据对齐规则:
a、一个char(占用1-byte)变量以1-byte对齐。
b、一个short(占用2-byte)变量以2-byte对齐。
c、一个int(占用4-byte)变量以4-byte对齐。
d、一个long(占用4-byte)变量以4-byte对齐。
e、一个float(占用4-byte)变量以4-byte对齐。
f、一个double(占用8-byte)变量以8-byte对齐。
g、一个long double(占用12-byte)变量以4-byte对齐。
h、任何pointer(占用4-byte)变量以4-byte对齐。
64位系统下:
a、一个long(占用8-byte)变量以8-byte对齐。
b、一个double(占用8-byte)变量以8-byte对齐。
c、一个long double(占用16-byte)变量以16-byte对齐。
d、任何pointer(占用8-byte)变量以8-byte对齐。
2、结构体数据对齐
结构体数据对齐,是指结构体内的各个数据对齐。在结构体中的第一个成员的首地址等于整个结构体的变量的首地址,而后的成员的地址随着它声明的顺序和实际占用的字节数递增。为了总的结构体大小对齐,会在结构体中插入一些没有实际意思的字符来填充(padding)结构体。
在结构体中,成员数据对齐满足以下规则:
a、第一个成员在结构体变量偏移量为0的地址处。
b、其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数与该成员大小的较小值。
VS中默认的值为8
gcc中的默认值为4
c、结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的
整数倍。
d、如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,
结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
b、其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数与该成员大小的较小值。
VS中默认的值为8
gcc中的默认值为4
c、结构体总大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的
整数倍。
d、如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,
结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
#include<stdio.h>int main(){struct{char a;int b;short c;char d;}dataAlign; struct {char a;char d;short c;int b;}dataAlign2;printf("dataAlign:%d\ndataAlign2:%d\n",sizeof(dataAlign),sizeof(dataAlign2));return 0;}得到的结果如下:
首先来看dataAlign,第一个成员等于结构体变量首地址,偏移量为0,第二个成员为int=4,为了满足规则b,需要在第一个成员之后填充3-byte,让它相对于结构体首地址偏移量为4,结合运行结果,可知&dataAlign.a = 0x01109140,而&dataAlign.b = 0x01109144,它们之间相隔4-byte,0x01109141~0x01109143三个字节被0填 充。第三个成员short=2,无需填充满足规则b。第四个成员char=1,也不需要填充。结构体总大小相加4 + 4 + 2 + 1 = 11。同样最后需要验证规则c,结构体中数据类型大小最大为第二个成员int=4,比VC默认对齐模数8小,故这个结构体的对齐模数仍然为4,显然11 mode 4 != 0,故为了满足规则c,需要在char后面填充一个字节,这样结构体变量dataAlign的总大小为4 + 4 + 2 + 2 = 12。
再来看dataAlign2,第一个成员的地址等于结构体变量的首地址,第二个成员char类型,为了满足规则b,它相对于结构体的首地址的偏移量必须 是char=1的倍数,由于前面也是char,故不需要在第一个和第一个成员之间填充,直接满足条件。第三个成员short=2如果要满足规则b,也不需 要填充,因为它的偏移量已经是2。同样第四个也因为偏移量int=4,不需要填充,这样结构体总共大小为8-byte。最后来验证规则c,在VC中默认 的#pragma pack(n)中的n=8,而结构体中数据类型大小最大的为第四个成员int=4,故对齐模数为4,并且8 mode 4 = 0,所以满足规则c。这样整个结构体的总大小为8。 0 0
- 关键字 对齐 内存对齐
- 内存对齐
- 内存对齐
- 内存对齐
- 内存对齐
- 内存对齐
- 内存对齐
- 内存对齐
- 内存对齐
- 内存对齐
- 内存对齐
- 内存对齐
- 内存对齐
- 内存对齐
- 内存对齐
- 内存对齐
- 内存对齐
- 内存对齐
- YOYO天气
- 蜜蜂训练2044
- 表单 模板(很实用)
- Docker大会的新福利:LinuxKit 和 Moby 开源项目
- 数据库的三个范式
- 内存对齐
- 【模拟】洛谷 P1086 花生采摘
- excel导入导出
- 基于vue2写的上拉加载
- rc文件 资源读取路径
- poj解题报告——poj 1493 Machined Surfaces
- 一个java高级工程师的进阶之路【转】
- cookie 和session 的区别详解
- lvs+keepalived主主模式