结构体对齐

写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的变量总长度要大,这是怎么回事呢?讲讲字节对齐吧.

/******************************分割线

如果体系结构是不对齐的,A中的成员将会一个挨一个存储,从而sizeof(a)为11。显然对齐更浪费了空间。那么为什么要使用对齐呢?
体系结构的对齐和不对齐,是在时间和空间上的一个权衡。对齐节省了时间。假设一个体系结构的字长为w,那么它同时就假设了在这种体系结构上对宽度为w的数据的处理最频繁也是最重要的。它的设计也是从优先提高对w位数据操作的效率来考虑的。比如说读写时.............此处省略50万字

***********************************************************/

上面是你随便 google一下,人家就可以跟你解释的,一大堆的道理,我们没怎么多时间,讨论为何要对齐.直入主题,怎么判断内存对齐规则,sizeof的结果怎么来的,请牢记以下3条原则:(在没有#pragma pack宏的情况下)

1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储。

2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)

3:收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的整数倍.不足的要补齐.

等你看完此3条原则,2分钟已经过去,抓紧时间,实战3分钟:

typedef struct bb
{
 int id;             //[0]....[3]
 double weight;      //[7].....[15]      原则1
 float height;      //[16]..[19],总长要为8的整数倍,补齐[20]...[23]     原则3
}BB;

typedef struct aa
{
 char name[2];     //[0],[1]
 int  id;         //[4]...[7]          原则1

 double score;     //[8]....[15]    
 short grade;    //[16],[17]        
 BB b;             //[24]......[47]          原则2
}AA;

int main()
{
  AA a;
  cout<<sizeof(a)<<" "<<sizeof(BB)<<endl;
  return 0;
}

结果是

48 24
ok,上面的全看明白了,内存对齐基本过关.

再讲讲#pragma pack().

在代码前加一句#pragma pack(1),你会很高兴的发现,上面的代码输出为

32 16
bb是4+8+4=16,aa是2+4+8+2+16=32;

这不是理想中的没有内存对齐的世界吗.没错,#pragma pack(1),告诉编译器,所有的对齐都按照1的整数倍对齐,换句话说就是没有对齐规则.

明白了不?

那#pragma pack(2)的结果又是多少呢?对不起,5分钟到了,自己去测试吧.

 

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/hairetz/archive/2009/04/16/4084088.aspx

### 结构体对齐原理 结构体对齐的核心在于优化 **数据存取执行效率** 和减少不必要的 **存储空间浪费** 的平衡[^1]。在嵌入式系统开发中,这种权衡尤为重要,因为内存资源有限而性能需求较高[^2]。 #### 数据对齐规则 1. **成员变量的对齐位置**: - 第一个成员始终位于偏移量为 `0` 的地址上。 - 后续成员会根据其类型的大小和编译器设定的最大对齐数进行调整,使其地址是对齐数的整数倍。对齐数通常是该成员类型大小与全局默认对齐数之间的最小值[^5]。 2. **整体结构体大小**: - 整个结构体的大小会被扩展为其内部最大对齐数的整数倍。这样可以确保当多个相同结构体组成数组时,每个结构体实例仍然能够保持良好的对齐状态[^4]。 3. **嵌套结构体处理**: - 如果结构体内包含另一个子结构体,则子结构体会以其自身的最大对齐数为准进行填充并扩展至合适的边界长度;最终整个父级结构体也会基于所有成员(包括嵌套部分)的最大对齐数值做进一步扩充。 ### 实现方法 可以通过预处理器指令或者特定函数来改变默认行为: - 使用 `#pragma pack(n)` 设置新的字节打包模式 (n 表示指定的新对齐单位),从而强制覆盖原有自动计算出来的对齐策略; ```c #include <stdio.h> #pragma pack(1) // 手动设置紧凑排列 typedef struct { char a; int b; short c; } MyStruct; int main() { printf("Size of MyStruct: %lu\n", sizeof(MyStruct)); // 输出应为7而非通常情况下的12或更多 return 0; } ``` - 利用标准库头文件 `<stdalign.h>` 提供的功能实现更灵活精确地控制对象间的相对定位关系。 另外需要注意的是,在实际项目里修改这些参数可能带来兼容性和移植性方面的问题,因此需谨慎操作。 ### 示例分析 假设存在如下定义: ```c struct Example { char ch; /* size=1 */ double db; /* size=8 */ }; ``` 如果没有特别指示,默认情况下可能会有以下布局: | 地址 | 类型 | |------|------------| | 0x00 | char(ch) | | 0x01 ~ 0x07 | 填充位 | | 0x08 ~ 0x10 | double(db)| 这里为了使双精度浮点数能高效加载到寄存器内工作,它前面预留了足够的空白区域作为补偿措施。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值