关于伟创 伟创新闻 伟创案例 网站套餐 联系方式
只做吸引客户的精品站!

C++中的内存对齐

洛阳软件开发师 / 2013/3/2 8:10:20
[核心提示] 因为CPU每次都是从以2字节(16位CPU)或是4字节(32位CPU)的整数倍的内存地址中读进数据的。
C++中的内存对齐

关于内存对齐

一:

1.什么是内存对齐

假设我们同时声明两个变量:

char a;

short b;

用&(取地址符号)观察变量a,

b的地址的话,我们会发现(以16位CPU为例):

如果a的地址是0x0000,那么b的地址将会是0x0002或者是0x0004。

那么就出现这样一个问题:0x0001这个地址没有被使用,那它干什么去了?答案就是它确实没被使用。因为CPU每次都是从以2字节(16位CPU)或是4字节(32位CPU)的整数倍的内存地址中读进数据的。如果变量b的地址是0x0001的话,那么CPU就需要先从0x0000中读取一个short,取它的高8位放入b的低8位,然后再从0x0002中读取下一个short,取它的低8位放入b的高8位中,这样的话,为了获得b的值,CPU需要进行了两次读操作。

 

但是如果b的地址为0x0002,

那么CPU只需一次读操作就可以获得b的值了。所以编译器为了优化代码,往往会根据变量的大小,将其指定到合适的位置,即称为内存对齐(对变量b做内存对齐,a、b之间的内存被浪费,a并未多占内存)。

2.结构体内存对齐规则

结构体所占用的内存与其成员在结构体中的声明顺序有关,其成员的内存对齐规则如下:

(1)每个成员分别按自己的对齐字节数和PPB(指定的对齐字节数,32位机默认为4)两个字节数最小的那个对齐,这样可以最小化长度。

(2)复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度。

(3)结构体对齐后的长度必须是成员中最大的对齐参数(PPB)的整数倍,这样在处理数组时可以保证每一项都边界对齐。

(4)计算结构体的内存大小时,应该列出每个成员的偏移地址,则其长度=最后一个成员的偏移地址+最后一个成员数的长度+最后一个成员的调整参数(考虑PPB)。

下面举例说明上述规则:

#include

#pragma pack(2) //指定PPB为2

struct T{

char a; //偏移地址0

int b; //偏移地址2

char c; //偏移地址6

};

#pragma pack() //恢复原来默认PPB,32位下为4

int main(int argc,char * argv[])

{

printf("sizeof(struct T));

return 0;

}

最后输出的结果为:8。语句#pragma pack(2)的作用是指定结构体按2字节对齐,即PPB=2。分析如下:

变量a默认为1字节,PB=2,所以a按1字节对齐,a的偏移地址为0。

变量b默认为4字节(在32位机器中int为4字节),PB=2,所以b按2字节对齐,b的偏移地址为2。

变量c默认为1字节,PB=2,所以c按1字节对齐,偏移地址为6。

此时结构体的计算出的字节数为7个字节。最后按规则3,结构体对齐后的字节数为8。sizeof(T)=6+1+1=8

3.范例

(1)#pragma pack(2) //指定PPB为2

struct T{

char a; //偏移地址0

char b; //偏移地址1

int c; //偏移地址2

};

则sizeof(T)=最后一个成员的偏移地址+最后一个成员数的长度=2+4=6。

(2)struct T1{

char a; //偏移地址0

char b; //偏移地址1

int c; //偏移地址4

};

struct T2{

char a; //偏移地址0

int b; //偏移地址4

char c; //偏移地址8

};

PPB=4,则sizeof(T1)=4+4=8;sizeof(T2)=8+1=9,9不能整除4,故调整数为3,即sizeof(T2)=8+1+3=12

4.注意的问题

(1)字节对齐取决于编译器;

(2)一定要注意PPB大小,PPB大小由pragam pack(n)指定;

(3)结构体占用的字节数要能被PPB整除。

二:

(1)sizeof也可以对一个函数调用求值,其结果是函数返回类型的大小,函数并不会被调用。

(2)终于搞懂struct结构体内存分配问题了,结构体中各个成员字节对齐遵循以下几个原则:

1.结构体每个成员相对于结构体首地址的偏移量(offset)都是(这个)成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal

adding);

例如有以下一个结构体

struct

ex {

int i;

char t;

int n;

}

第1个成员偏移量为0,是int型成员大小4(假设这太机器的整型长度占4个字节)的整数倍。

第2个成员

t

为char型,他的大小为1,首先假设在成员i和t之间没有填充字节,由于i是整型,占4个字节那么在没有填充之前,第2个成员t相对于结构体的偏移量为4,他是t成员大小1的4倍,符合此条件,所以系统在给结构体第2个成员分配内存时,不会在i和t之间填充字节以到达对齐的目的。

当分配结构体第3个成员n时,首先发现是一个整型数据,大小为4,没有填充之前,n相对于结构体首地址偏移量为:前面2个成员+填充字节=5,所以当系统发现5不是4(成员大小)的整数倍时,会在成员t之后(或者说n之前)填充3个字节,以使n的偏移量到达8而成为4的整数倍。这样这个结构体占用内存情况暂时为4+1+3+4。

2.结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing

padding)。

上面的结构体内存分配以后还要看是否满足此条件,假设在最末一个成员之后不需填充字节数,那么这个结构体的大小为12。而ex结构体中最宽基本类型成员为int,大小为4,12为4的整数倍,所以无须再在最末一个成员之后加上填充字节了。所以sizeof(ex)=12;

如果一个结构体如下所示struct

ex1{

int i;

char t;

int n;

char add;

}

那么sizeof(ex1)

=16;原因就是在最后一个成员之后填充了3个字节。

3.还有一个额外的条件:结构体变量的首地址能够被其最宽基本类型成员的大小所整除;

4.对于结构体成员属性中包含结构体变量的复合型结构体再确定最宽基本类型成员时,应当包括复合类型成员的子成员。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。

5总结出一个公式:结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:

sizeof( struct ) = offsetof( last item ) + sizeof( last item ) +

sizeof( trailing padding )

尊重作者原创 除非特别声明,伟创科技所有均为伟创原创报道,转载请注明原文链接。
原文地址:http://www.lywhy.com/SoftWare/View.asp?id=358  所属类别:软件开发
相关内容
洛阳软件开发需要多少钱? 2019/12/6
10种不同类型的软件开发 2019/11/5
如何更好的完成软件开发的项目 2018/9/18
伟创技术-婷婷:身为.NET程序员的断想 2017/2/18
【洛阳网络公司技术分享】身为.NET程序员的断想 2016/1/28
猜你喜欢
详细的产品介绍及多媒体资料有助于提高网站转化率 2012/10/29
网站设置为当前窗口打开页面有可能会让你失去客户 2013/5/2
贺伟创科技签约洛阳天旗画框工艺有限公司网站制作项目 2014/9/27
做网站同样需要做到将工作做精,将服务做细! 2019/4/22
数据生活在此:Google街景带你参观数据中心 2012/10/18
在做网站前请先了解这些 2013/4/6
伟创科技的技术实力如何?优势在哪里? 2014/8/4
网站制作规划的紧张之处是什么 2018/3/19
激烈的竞争是网络营销产生的现实基础 2012/10/7
为什么仍还用C编码? 2013/3/18
伟创热点
关于我们
公司简介
我们的优势
企业文化
公司愿景
加入伟创
伟创官方博客
金牌项目
网站建设
网站优化
软件开发
整合设计
网站运营
网站套餐
基础型网站
展示型网站
商务型网站
购物、商店型网站
FLASH动画型网站
行业、门户型网站
帮助中心
客户中心
公司SEO培训
seo顾问服务
支付方式
联系我们
我们的位置
关注我们
新浪微博
腾讯微博
人人小站
QQ空间推荐
花瓣网
建站百科全书
Copyright 2007-2012 LYWHY.Inc Sitemap 豫ICP备12012069号-1
Links
洛阳百科
建站百科