您的位置:首页 > 其它

由结构体对齐而引发的思考。。。(一)

2017-07-29 16:40 218 查看
(由于本文初期在CSDN中编辑的不是太好,现在将其发表于看雪论坛中,具体链接如下:
https://bbs.pediy.com/thread-222967.htm

)
从结构体对齐到C++类对象内存模型之一结构体对齐
结构体与类在c++中非常相似,他们的内存排布是一个比较有意思的知识点,故而准备写一些文章来探讨这些问题。首先从结构体的内存对齐说起,所有的测试环境都是vs201X,其他环境自行实验

一实验

结构体变量内存中成员的排布:从第一个声明的成员依次向下排列,结构体对象中的内存中成员的排布如图所示:

也就是说在一个结构体类型的数据的内存中,结构体数据的地址开始于第一个声明的成员的地址,结束于最后一个成员的地址。在他们中间,按照声明的顺序存储着所有的数据成员,但是事实并非这么简单,还有内存对齐的问题。
       对于这样的结构体:

 
struct Test {
    char
a;
    double
b;
    char
c;
};
int _tmain(intargc,_TCHAR*argv[])
{
    Test 
Teobj;
    Teobj.a ='a';
    Teobj.b = 1564654.325;
    Teobj.c ='b';
    cout
<< sizeof(Test);
}

输出结果是:24

         查看Teobj的内存是这个样子的:

         

0x0032F9CC是Teobj的起始地址,也是它的第一个成员a的起始地址,但是在a后面没有仅接着就存储b,而是空了7个字节之后再存储b,b占了8个字节,之后c占据了一个字节后,整个结构体并未结束,在其后又空置了7个字节,所以整个结构体是24个字节。对于还不了解内存对齐的人,是很费解的。

         二规则

         那么内存对齐的规则是什么呢?经过查找与验证,为以下三点

         规则1:数据的第一个成员存储在结构体的起始位置,偏移为0

         规则2.1:数据的后续成员存储的偏移位置为某一个数的整数倍

         规则2.2:上个规则中的某一个数为编译器默认的对齐数与这个数据成员的字节数这两个数中的较小值。

         规则3:整个结构体的尺寸为结构体中每一次安排的某一个数中的最大值的最小整数倍。

         下面结合例子对以上规则进行解释:

         第一个成员a为字符型,占一个字节,存储的位置是0x0032F9CC,存储之后,第二个成员b为双精度浮点型,占8个字节,同时编译器默认规定的对齐数为8,这两个数取较小值,还是8,所以它存储的位置偏移应该为8的整数倍,恰0x0032F9D4-0x0032F9CC为8,故而在0x0032F9D4这个地方存储b占用8个字节。之后准备开始存储c,c是字符型,占据一个字节,系统默认对齐数为8,二者取其小,它存储的地址应该是1的整数倍,很明显,任何偏移都是1的整数倍,直接存在了b的后面。到这里本该结束了,但是还有规则3.在进行b的存储的时候选出来的某个数是8,在存储c的时候选出来的某个数是1,在8和1中选出一个最大值,结构体的大小应该为8的最小整数倍,现在的结构体大小为8+8+1也就是17,最小整数倍只能是24了。所以在c的后面又空置了7个字节。促成了结构体的24个字节的大小。

         还有两点要说明:

         1 以上提到了一个编译器默认的对齐数,这个数是可以更改的。使用#pragma  pack (1//2//4//8//16)来更改,只能改为1,2,4,8,16中的一个值。

         2  在网络传输,使用结构体指针指向某一个数据区获取数据,读取文件等时候,经常由于结构体的对齐问题而出错,是一个值得注意的问题。

        三尾声 

        以下这个例子能够再次熟悉结构体的对齐:

struct Test {
    char
a;
    double
b;
    int 
n;
};
int _tmain(intargc,_TCHAR*argv[])
{
    Test
obj;
    obj.a ='c';
    obj.b = 889089;
    obj.n = 1234;
    cout <<
sizeof(Test);
}

输入结果为:24

 

struct Test {
    char
a;
    int  
n;
    double
b;
};
int _tmain(intargc,_TCHAR*argv[])
{
    Test
obj;
    obj.a ='c';
    obj.b = 889089;
    obj.n = 1234;
    cout <<
sizeof(Test);
}
输出结果为:16

         一样的成员变量,顺序不一样造成了整个结构体大小不同。主要原因就是结构体对齐的问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: