注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

一路

To find the final symmetry & beauty

 
 
 

日志

 
 
 
 

SGI STL源码阅读笔记8 内存对齐总结[原创]  

2011-02-17 01:26:43|  分类: c++学习笔记 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

    这篇只做一个小的总结,不求全面,够用就好了。其实这部分不全是SGI STL的源代码,我还参考了微软的STL源代码,就叫它M$ STL。因什么内存要对齐可以网上查找,到处都有解释,一句话,为了CPU方便和提高速度,这里只关心如何对齐。

一、#pragma pack宏

微软的STL核心文件是credefs.h,里面有这个宏。查了一下msdn终于搞清楚这个宏的意思了。这个宏有好几种表现形式,可以有push和pop参数。这里为了简单就只说这个宏的数值参数的情况。为了解更多可以参考http://msdn.microsoft.com/zh-cn/library/2e70t5y1(v=VS.90) 这个宏可接受的参数是1,2,4,8,16的其中之一,它只会影响定义这个宏之后第一个类或是结构体的内存布局。设置之后会以这个数字的倍数为内存对齐字节。其实问题还有点小复杂,考虑如下代码。

#include<iostream>

#include<cstddef>

using namespace std;

#pragma pack(8)

class A

{

public:

double arr[2];

};

#pragma pack(8)

class B

{

public:

char var;

A var_a;

int c;

};

#pragma pack(8)

class C

{

public:

char var;

};

int main()

{

cout<<sizeof(A)<<endl;

cout<<sizeof(B)<<endl;

cout<<sizeof(C)<<endl;

cout<<"*******************************"<<endl;

cout<<offsetof(B,var)<<endl;

cout<<offsetof(B,var_a)<<endl;

cout<<offsetof(B,c)<<endl;

system("pause");

return 0;

}

类A是两个长度的double数组,长度是16个字节,这没有问题。看类B的第一个成员,它的第一个成员占一个字节,这时对齐方式会选择最大成员的对齐字节,也就是8和pack参数的进行比较,较小者会被选为类的对齐字节,这里是比较结果是8,因此第一个char虽然只占一个字节,但是其它7个字节会被填充。下一个成员var会在第9个字节开始。 相应的int会在第25个字节开始,它只占四个字节,其余的字节会被填充,它的大小应该是8+16+8=32字节。类C只有一个成员,但是它的成员的最大类型为char,因此虽然设置pack参数为8,它的齐还是以一个字节对齐,不会对它填充。因此它的大小应该为1.offsetof是一个宏,它会返回一个类中某个成员所在类的开始它节,利用它可以查看一些变量实际对齐位置。程运行结果如下。

16

32

1

*******************************

0

8

24

二、offsetof宏的实现,查看类成员在类中的开始位置

它的实现代码在微软STL的stddef.h文件中,原文如下

我们只看最后一种最简单的,其它的都是在支持的情况下使用最安全的特性。

#define offsetof(s,m) (size_t)&(((s *)0)->m)

这里的方法是把0强转为一个结构体s的指针,之后取这个指针指向的s结构体成员m的地址,这相地址当然就是相对0的地圵,之后把这个地址强转为一个size_t类型,size_t就是一个无符号整数类型,很简单的代码,有些公司就考这些奇怪的东西,不知为什么。

三、内存对齐函数的实现代码

    我们如果要实现自己的内存管理基本都要涉及一个内存对齐函数的设计,之后把对象放到指定的内存上去。注意我们一般都是把一个对象的大小对齐到一个二的整数幂的整数倍的上。这个在STL中就有,它是这样的

这个_ALIGN 是一个二的幂,也就是说它的内存表示只有一个1,因此把它减1并取反就是把这个比这个1高的位和它本身全变成1,其它的全是0,之后把这个数与要对齐的数字与_ALIGN-1的和相与,这么做的目地是只要__bytes的比原_ALIGN 中1低的位中有1,那么就会产生对比这个1高的位有一个进位,否则(低位全0的情况)没有这个进位,之后相与把低位的0全去掉,这样就达到了上调大小的目地。仔细计算一下,这个函数在一般机器上只会用到两条汇编指令,十分高效。

Ref:

[1] http://msdn.microsoft.com/zh-cn/library/2e70t5y1(v=VS.90)

[2] http://msdn.microsoft.com/zh-cn/library/71kf49f1(v=VS.90)

  评论这张
 
阅读(877)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017