面试常考,项目易错,长文详解C/C++中的字节对齐( 三 )

在数据成员完成各自对齐之后 , 结构(或联合)本身也要进行对齐 , 对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中 , 比较小的那个进行 。

  1. 1#pragma pack(4)struct m{int a;short b;int c;};int main(){cout <<"结构体m的大小:"<< sizeof(m) << endl;cout << endl;// 获得成员a相对于m储存地址的偏移量int offset_b = offsetof(struct m, a);cout <<"a相对于m储存地址的偏移量:"<< offset_b << endl;system("pause");return 0;}
    面试常考,项目易错,长文详解C/C++中的字节对齐文章插图
    从运行结果来看我们可以证实上面内存对齐规则的第一条:第一个数据成员放在offset为0的地方;现在咱来看看上面结构体是如何内存对齐的;先用代码打印它们每个数据成员的存储地址的偏移量
    //编译器:来源:技术让梦想更伟大//作者:李肖遥#include#includeusing namespace std;#pragma pack(4)struct m{int a;short b;int c;};int main(){cout <<"结构体m的大小:"<< sizeof(m) << endl;cout << endl;int offset_b = offsetof(struct m, a);// 获得成员a相对于m储存地址的偏移量int offset_b1 = offsetof(struct m, b);// 获得成员a相对于m储存地址的偏移量int offset_b2 = offsetof(struct m, c);// 获得成员a相对于m储存地址的偏移量cout <<"a相对于m储存地址的偏移量:"<< offset_b << endl;cout << "b相对于m储存地址的偏移量:" << offset_b1 << endl;cout << "c相对于m储存地址的偏移量:" << offset_b2 << endl;//system("pause");return 0;}
    面试常考,项目易错,长文详解C/C++中的字节对齐文章插图
    在此c在结构体中偏移量为8加上它自身(int)4个字节 , 刚好是12(c的开始位置为8 , 所以要加它的4个字节)
    上面内存结束为11 , 因为0-11 , 12是最大对齐数的整数倍 , 故取其临近的倍数 , 所以就取4的整数倍即12;上图中我用连续的数组来模仿内存 , 如图是它们的内存对齐图;如果将最大内存对齐数改为8 , 他将验证内存对齐规则中的第3条 。
    如果将其改为2 , 会发生什么:我们来看看:
    //编译器:来源:技术让梦想更伟大//作者:李肖遥#include#includeusing namespace std;#pragma pack(2)struct m{int a;short b;int c;};int main(){cout <<"结构体m的大小:"<< sizeof(m) << endl;cout << endl;int offset_b = offsetof(struct m, a);// 获得成员a相对于m储存地址的偏移量int offset_b1 = offsetof(struct m, b);// 获得成员a相对于m储存地址的偏移量int offset_b2 = offsetof(struct m, c);// 获得成员a相对于m储存地址的偏移量cout <<"a相对于m储存地址的偏移量:"<< offset_b << endl;cout << "b相对于m储存地址的偏移量:" << offset_b1 << endl;cout << "c相对于m储存地址的偏移量:" << offset_b2 << endl;//system("pause");return 0;}
    面试常考,项目易错,长文详解C/C++中的字节对齐文章插图
    对于这个结果 , 我们按刚才第一个例子我所分析的过程来分析这段代码 , 得到的是10;故当我们将#pragma pack的n值小于所有数据成员长度的时候 , 结果将改变 。
    对齐的作用和原因各个硬件平台对存储空间的处理上有很大的不同 。 如果不按照适合其平台要求对数据存放进行对齐 , 可能会在存取效率上带来损失 。
    比如有些平台每次读都是从偶地址开始 , 如果一个int型在32位地址存放在偶地址开始的地方 , 那么一个读周期就可以读出;
    而如果存放在奇地址开始的地方 , 就可能会需要2个读周期 , 并对两次读出的结果的高低字节进行拼凑才能得到该int数据 。 那么在读取效率上下降很多 , 这也是空间和时间的博弈 。


    推荐阅读