再谈字节对齐

时隔两年,再回头看当初那个不懂事的我,发现那篇文章写的有问题,特来更正。原文放到后边。感谢王世超同学帮我在各个平台验证。2014/9/3

=======以下是更正内容,若还有疏漏和错误,请您不吝告知========

依旧,我理解的字节对齐就是各个成员地址上的对齐,那对齐的规则有如下几条:

1.每个变量成员的地址是可以被min(寻址总线,内置类型变量大小)整除,比如在64位程序中,short的地址必须是要被2整除的,而在32位程序中double则是要能被4整除。

2.结构体(类)的总大小是要能被min(寻址总线,最大内置类型变量大小)整除的,为了保证结构体数组下一个的地址满足同样的条件。

3.成员变量的相对于结构体(类)的偏移地址要能被其大小整除。

4.结构体(类)大小是其包含最大内置类型变量大小的整倍数。

5.结构体(类)包含了其他结构体(类),要看其内部最大内置类型的大小来选择对齐。


基本规则如上,但在不同平台表现不同:

linux(RHEL5 64位和CentOS6 32位):需要满足规则1,2,5。

windows(win7 32位和64位 vs2010):需要满足规则1,3,4,5。


=============以下是原文=============

在网上看了n多字节对齐的文章,看完之后也是将懂不懂的,于是决定还是自己来研究一下,补充一下网上文章所没讲明白的。
首先,字节对齐是为了cpu能更快的存取数据。我之前看到的很多文章主要是在抽象数据类型的大小方面讲解对齐,这个本来是很好理解的,但是这也不免给我这样一知半解的人留下一个错误的印象:只有在涉及抽象数据类型的大小才存在字节对齐的问题。
深入了解之后,发现:字节对齐是针对每个数据项的起始地址与其字节大小对齐。每个数据,无论全局变量还是局部变量,无论是基本类型的对象还是抽象数据类型的对象的起始地址都要与其基本类型字节大小对齐。在linux中对齐是以2、4为基准的,而在windows中是其实地址必须是数据字节大小的倍数。简单来说,一个short型的地址必须是2的倍数,也就是说地址的最低位是0。int型的地址最低2位必须是00。在windows中,double类型的起始地址最低三位必须是000。
当了解这个情况以后,再来判断诸如结构体的大小就明白很多了。如下:
在windows中这个结构体A

struct A{
    char c1;
    int i;
    char c2;
    double d;
    char c3;
}
的大小是多少呢?一一来分析,先来假设c1的起始地址是000000,i的起始地址本来因该是000001,但是由于字节对齐的规则,所以i跑到了000100。依次,c2的地址是001000,d的地址就是001100(linux)或010000(windows)。c3的地址是011000。那么它的大小就是末地址减去初始地址喽:011001 - 000000 = 25字节。
那么接下来再列举一个相信就明白了:
struct B{
    char c1[9]; // c1: 0x0000
    double d1;		// d1: 0x0010
    short si;// si: 0x0018
    double d2;// d2: 0x0020
    char c2[5];// c2: 0x0028
    int i;// i:  0x0030 
}
在windows中B的大小是52字节。
那么,怎么排列这些数据可以占更少的空间呢?
struct C{
    char c1[9];// c1: 0x0000
    char c2[5];// c2: 0x0009
    short si;// si: 0x000E
    double d1;// d1: 0x0010
    double d2;// d2: 0x0018
    int i ;// i : 0x0020
}
在windows中C的大小为36字节。如此,相信大家了解了字节对齐了吧。
曾经认为盖茨那厮,在设计时一点也不节约,所以我原来常常觉得这样太浪费了。但是后来我发现,相对来说,内存便宜的多,浪费一点内存带来的性能提升还是客观的。



你可能感兴趣的:(初学c++,windows,struct,c,linux)