有关-内存对齐-的总结
2011-12-21 09:42
211 查看
今日在工作中遇到了要宣讲内存对齐的内容,及仔细的总结了有关内存对齐的相关知识。
要点:在保证可读性的前提下,合理排列结构中成员的顺序(按照由小到大的顺序排列),可以提高内存利用率。
例子:
例:
#pragma pack(push,1)
typedef struct _structAddressAndSizeTest{
BYTE cbTest;
wchar_t cTest;
int nTest;
double dTest;
} structAddressAndSizeTest,*pStructAddressAndSizeTest;
#pragma pack (pop)
结构体地址:12f4ac
结构体成员地址:12f4ac,12f4ad,12f4af,12f4b3
结构体中成员类型所占字节大小:1,2,4,8
结构体所占字节大小:15
我们将结构体成员的顺序更改一下,将BYTE放在最后
typedef struct _structAddressAndSizeTest{
wchar_t cTest;
int nTest;
double dTest;
BYTE cbTest;
} structAddressAndSizeTest,*pStructAddressAndSizeTest;
我们将其结构体的信息打印,打印的结构体成员地址顺序按照结构体成员声明顺序排列。
结构体成员地址: 12f4a4,12f4a8,12f4ac,12f4b4,
结构体所占字节大小:24
由此可见,合理排列结构中的成员顺序至关重要,正确写法请参照红色字体部分。
对例子的分歧理解:
Subject: 答复: “每日一帖”宣讲编码规范(2011年12月20日)
关于第三条我补充说明一下:
1)#pragma pack(push,1)和#pragma pack (pop)不知道是什么作用,估计我们项目中也用不到,所以就不考虑了。
2)第一个结构体变量对齐方式如下:
BYTE cbTest; 1 + 1(空闲)
wchar_t cTest; 2
int nTest; 4
double dTest; 8
所以共2+2+4+8 = 16字节。原文中该值为15,不对。(其实这个理解是错误的)
3)第二个结构体变量对齐方式如下:
wchar_t cTest; 2 + 2(空闲)
int nTest; 4
double dTest; 8
BYTE cbTest; 1 + 7(空闲)
所以共4+4+8+8 = 24字节。
注意:
以下内容是在网上找的C语言相关的内存对齐的资料,希望对大家理解内存对齐有所帮助。
一、内存对齐的原因
大部分的参考资料都是如是说的:
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
二、对齐规则
每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。
规则:
1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
3、结合1、2可推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。
Win32平台下的微软C编译器(cl.exefor 80×86)的对齐策略:
1) 结构体变量的首地址是其最长基本类型成员的整数倍;
备注:编译器在给结构体开辟空间时,首先找到结构体中最宽的基本数据类型,然后寻找内存地址能是该基本数据类型的整倍的位置,作为结构体的首地址。将这个最宽的基本数据类型的大小作为上面介绍的对齐模数。
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
备注:为结构体的一个成员开辟空间之前,编译器首先检查预开辟空间的首地址相对于结构体首地址的偏移是否是本成员的整数倍,若是,则存放本成员,反之,则在本成员和上一个成员之间填充一定的字节,以达到整数倍的要求,也就是将预开辟空间的首地址后移几个字节。
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员之后加上填充字节(trailing padding)。
备注:结构体总大小是包括填充字节,最后一个成员满足上面两条以外,还必须满足第三条,否则就必须在最后填充几个字节以达到本条要求。
4) 结构体内类型相同的连续元素将在连续的空间内,和数组一样。
5) 如果结构体内存在长度大于处理器位数的元素,那么就以处理器的倍数为对齐单位;否则,如果结构体内的元素的长度都小于处理器的倍数的时候,便以结构体里面最长的数据元素为对齐单位。
最后结论:
例子与#pragma pack(n)有一定关系,依个人理解,结构体所占字节应该是15,因为此时是#pragma pack (1),当修改成#pragma pack (2),此时的对齐系数旧成2了
结构体所占字节应该是16;
具体请看如下补充:
内存对齐有的地方叫做字节对齐,主要理解struct等复合结构在内存中的存储结构,这里引用其他地方对内存对齐的解释:计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个对其参数k(通常它为4或8)的倍数,这就是所谓的内存对齐。
通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变对齐系数,对齐系数也叫对齐模数
在VC2005中查看编译器结构成员对齐
项目-》属性-》C/C++-》代码生成-》结构成员对齐-》默认值是8
我们当前编译器所使用的对齐系数是8
要点:在保证可读性的前提下,合理排列结构中成员的顺序(按照由小到大的顺序排列),可以提高内存利用率。
例子:
例:
#pragma pack(push,1)
typedef struct _structAddressAndSizeTest{
BYTE cbTest;
wchar_t cTest;
int nTest;
double dTest;
} structAddressAndSizeTest,*pStructAddressAndSizeTest;
#pragma pack (pop)
结构体地址:12f4ac
结构体成员地址:12f4ac,12f4ad,12f4af,12f4b3
结构体中成员类型所占字节大小:1,2,4,8
结构体所占字节大小:15
我们将结构体成员的顺序更改一下,将BYTE放在最后
typedef struct _structAddressAndSizeTest{
wchar_t cTest;
int nTest;
double dTest;
BYTE cbTest;
} structAddressAndSizeTest,*pStructAddressAndSizeTest;
我们将其结构体的信息打印,打印的结构体成员地址顺序按照结构体成员声明顺序排列。
结构体成员地址: 12f4a4,12f4a8,12f4ac,12f4b4,
结构体所占字节大小:24
由此可见,合理排列结构中的成员顺序至关重要,正确写法请参照红色字体部分。
对例子的分歧理解:
Subject: 答复: “每日一帖”宣讲编码规范(2011年12月20日)
关于第三条我补充说明一下:
1)#pragma pack(push,1)和#pragma pack (pop)不知道是什么作用,估计我们项目中也用不到,所以就不考虑了。
2)第一个结构体变量对齐方式如下:
BYTE cbTest; 1 + 1(空闲)
wchar_t cTest; 2
int nTest; 4
double dTest; 8
所以共2+2+4+8 = 16字节。原文中该值为15,不对。(其实这个理解是错误的)
3)第二个结构体变量对齐方式如下:
wchar_t cTest; 2 + 2(空闲)
int nTest; 4
double dTest; 8
BYTE cbTest; 1 + 7(空闲)
所以共4+4+8+8 = 24字节。
注意:
以下内容是在网上找的C语言相关的内存对齐的资料,希望对大家理解内存对齐有所帮助。
一、内存对齐的原因
大部分的参考资料都是如是说的:
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
二、对齐规则
每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。
规则:
1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
3、结合1、2可推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。
Win32平台下的微软C编译器(cl.exefor 80×86)的对齐策略:
1) 结构体变量的首地址是其最长基本类型成员的整数倍;
备注:编译器在给结构体开辟空间时,首先找到结构体中最宽的基本数据类型,然后寻找内存地址能是该基本数据类型的整倍的位置,作为结构体的首地址。将这个最宽的基本数据类型的大小作为上面介绍的对齐模数。
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
备注:为结构体的一个成员开辟空间之前,编译器首先检查预开辟空间的首地址相对于结构体首地址的偏移是否是本成员的整数倍,若是,则存放本成员,反之,则在本成员和上一个成员之间填充一定的字节,以达到整数倍的要求,也就是将预开辟空间的首地址后移几个字节。
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员之后加上填充字节(trailing padding)。
备注:结构体总大小是包括填充字节,最后一个成员满足上面两条以外,还必须满足第三条,否则就必须在最后填充几个字节以达到本条要求。
4) 结构体内类型相同的连续元素将在连续的空间内,和数组一样。
5) 如果结构体内存在长度大于处理器位数的元素,那么就以处理器的倍数为对齐单位;否则,如果结构体内的元素的长度都小于处理器的倍数的时候,便以结构体里面最长的数据元素为对齐单位。
最后结论:
例子与#pragma pack(n)有一定关系,依个人理解,结构体所占字节应该是15,因为此时是#pragma pack (1),当修改成#pragma pack (2),此时的对齐系数旧成2了
结构体所占字节应该是16;
具体请看如下补充:
内存对齐有的地方叫做字节对齐,主要理解struct等复合结构在内存中的存储结构,这里引用其他地方对内存对齐的解释:计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个对其参数k(通常它为4或8)的倍数,这就是所谓的内存对齐。
通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变对齐系数,对齐系数也叫对齐模数
在VC2005中查看编译器结构成员对齐
项目-》属性-》C/C++-》代码生成-》结构成员对齐-》默认值是8
我们当前编译器所使用的对齐系数是8
相关文章推荐
- 结构体内存对齐的补充说明与总结
- 【并行计算-CUDA开发】有关CUDA当中global memory如何实现合并访问跟内存对齐相关的问题
- 结构体(struct)的使用、内存分布以及字节对齐测试总结
- 有关内存对齐的问题
- 总结面试时没有回答上的设置内存对齐方式问题
- 结构体(struct)的使用、内存分布以及字节对齐测试总结
- 内存字节对齐总结
- 常见的与内存有关的错误总结
- C++笔记——有关内存对齐
- C语言内存对齐总结
- 知识点总结——结构体大小、内存对齐方式
- 内存字节对齐总结
- 内存字节对齐原则——总结
- 字节字符和整数转换-大小端转换-结构体内存(文件)对齐规则之总结
- 关于内存对齐的总结1
- 关于内存对齐的总结
- 关于内存对齐的总结1(看过的写的最清楚的)
- C/C++学习笔记8:内存中数据对齐的问题总结
- 与内存对齐有关的sizeof
- 总结面试时没有回答上的内存对齐问题