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


可以看到按照自然对齐 , 变量之间没有出现间隙 , 所以规则对齐也不用进行填充 , 而这里有颜色的方格有6个 , 也就是6个字节
按照规则对齐 , 6字节是此结构体中最大数据类型short的整数倍 , 因此此结构体为6字节 , 后面的空白不需理会 , 可以实际编译 。 一下运行 , 结果和分析一致为6个字节 。
double的情况我们知道32位处理器一次只能处理32位也就是4个字节的数据 , 而double是8字节数据类型 , 这要怎么处理呢?
如果是64位处理器 , 8字节数据可以一次处理完毕 , 而在32位处理器下 , 为了也能处理double8字节数据 , 在处理的时候将会把double拆分成两个4字节数进行处理 , 从这里就会出现一种情况如下:
typedef struct test_32{char a;char b;double c;}test_32;这个结构体在32位下所占内存空间为12字节 , 而在64位环境下所占内存空间为16字节 , 原因就是上述的处理方式不同导致的 , 32位下只能拆分成两个4字节进行处理 , 所以这里规则对齐将判定该结构体最大数据类型长度为4字节 , 因此总长度为4字节的整数倍 , 也就是12字节 。
而64位判定最大为8字节 , 所以结果也是8字节的整数倍:16字节 。 这里的结构体中的double没有按照自然对齐放置到理论上的8字节倍数地址处 , 我认为这里编译器也有根据规则对齐做出相应的优化 , 节省了4个多余字节 。
这部分各位可以按照上述规则自行分析测试 。
数组对齐值为:min(数组元素类型,指定对齐长度).但数组中的元素是连续存放,存放时还是按照数组实际的长度.
如char t[9],对齐长度为1,实际占用连续的9byte.然后根据下一个元素的对齐长度决定在下一个元素之前填补多少byte.
嵌套的结构体假设
struct A{......struct B b;......};对于B结构体在A中的对齐长度为:min(B结构体的对齐长度,指定的对齐长度).B结构体的对齐长度为:上述2中结构整体对齐规则中的对齐长度.举个例子
//编译器:来源:技术让梦想更伟大//作者:李肖遥#include #include using namespace std;#pragma pack(8)struct Args{char ch;double d;short st;char rs[9];int i;} args;struct Argsa{char ch;Args test;char jd[10];int i;}arga;输出结果:
面试常考,项目易错,长文详解C/C++中的字节对齐文章插图
改成#pragma pack (16)结果一样.这个例子证明了三点:

  • 对齐长度长于struct中的类型长度最长的值时,设置的对齐长度等于无用.
  • 数组对齐的长度是按照数组成员类型长度来比对的.
  • 嵌套的结构体中,所包含的结构体的对齐长度是结构体的对齐长度.
指针主要是因为32位和64位机寻址上,来看看例子
//编译器:来源:技术让梦想更伟大//作者:李肖遥#include #include using namespace std;#pragma pack(4)struct Args{int i;double d;char *p;char ch;int *pi;}args;结果如下| pack | 4 | 8 || —- | —- | —- || length | 32 | 40| args1 | 8 | 8 || args2 | 4 | 8 |
内存对齐的规则
  1. 数据成员对齐规则结构(struct)(或联合(union))的数据成员 , 第一个数据成员放在offset为0的地方 , 以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中 , 比较小的那个进行 。 (例如struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.) 。
  1. 结构体作为成员如果一个结构里有某些结构体成员,则结构体成员要从其内部”最宽基本类型成员”的整数倍地址开始存储.(例如struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.) 。