说说C语言和内存对齐

Monday, November 17th, 2008 154 views

我看东西,看得快,忘得也奇快。大概2星期重新研究过内存对齐,现在都快忘光了,于是赶紧再回忆一下。 :)

所谓内存对齐,即使得数据所在内存地址的起点应尽量对齐(是某个值的公倍数),而不是凌乱不堪的。一般我们把8个bit看成1一个byte,用byte来做存储的单位,其实也是一种内存对齐的机制——这样处理器访问数据只需要访问8的倍数即可。

内存对齐的目的很简单,这样有利于提供访问的速度(特别是在栈中)。对于对齐的内存地址,处理器访问一次即可得到,而未对齐的地址,可能需要访问两次才行。

那内存对齐的最小单位是什么呢?其实不同平台上不同的编译器都有自己的决定(猜的),编译器的这个决定叫做默认对齐系数。我们在自己编写程序的时候很少会去注意到这个对齐问题,这个很正常,因为这机制本身就应该是对程序员透明的。但是,我们还是能够在程序中觉察到对齐机制的存在。如果程序员没有正确意识到对齐机制的存在,有的时候它甚至会让程序的行为不正确。我举个小小的例子来说明下。
假设有这样一个结构体

typedef struct ex{
	int c1;
	char c2;
        int c3;
}ve;  /*  1  */

我的运行环境是gcc4.0+, ubuntu8.04, 32位单核cpu,sizeof(char)是1,sizeof(int)是4,猜猜sizeof(ve)的值会是多少?如果程序员不清楚内存对齐的概念的话会认为这个值是6,但其实是12。在这里面,有4个成员需要对齐,c1,c2,c3,ve,c1,c2,c3跟ve的对齐规则并不一致。

c1,c2,c3的对齐过程如下(对齐系数是4的前提下):假设第一个成员放在offset为0的位置,那么c1所占的内存就是[0~3],而c2所占的内存是[4],c3所占的内存不是[5~8],而是[8~12],但如果c3是char类型的话,c3所占的内存就是[5]。

所以结构体内成员的对齐规则如下:假设第一个成员的offset是0,则之后成员的对齐系数是系统的对齐系数(可以通过pragma pack(x)来指定)和自身长度两者间较小的值。比如,系统的对齐系数是4,而char的长度是1,那么char就按1对齐。而int的长度是4,于系统对齐系数一致,则按4对齐。

从上面这个规则,我们可以看到一个有趣的问题,结构体内,成员的摆放顺序不同,结构体所占空间是不同的。比如,

typedef struct ex{
	char c1;
	char c2;
        int c3;
}ve; /*  2  */

typedef struct ex{
	char c1;
	int c3;
        char c2;
}ve; /*  3  */

,前者所占的空间是8,而后者所占空间是12。但是对于程序的逻辑而言,两者的定义是完全一致的。了解对齐规则是有好处的,至少我们写出来的结构体空间占用更小些。 :)

说完了c1,c2,c3的对齐,下面说ve的对齐。sizeof(ve)的值事实上并不是如我们分析的c1,c2,c3对齐完之后所占空间的累加,它自身也是需要对齐的。结构体的对齐规则如下:取其成员中占用空间最长的值,我们的例子中是int类型,值是4,然后跟系统的对齐系数比较,取较小值为ve的对齐系数。如果我们在结构体2中,语句int c3;后面再加一句char temp;我们可以算出成员所占的空间是9,而ve所占的空间是12。

关于

我叫陈炬,正在天津大学计算机学院->知识工程与科学研究所攻读硕士研究生。今年应届。您可以在我的自我介绍获得更多关于我的信息

订阅我的Blog


本站RSS地址| [这是什么?]
订阅到Google Reader | 订阅到 抓虾 阅读器 | 订阅到 鲜果 阅读器

其他blog

我还有一个英文blog,非常的无聊,琐碎,许多的语法错误。请谨慎访问。
Find entries :