29、内存对齐与位域的面试题解析:经典面试题讲解、常见笔试题分析
面试的时候,内存对齐和位域几乎是必考题。说实话,我当年第一次面试就被问懵了——明明代码写得挺顺,一到结构体大小计算就翻车。后来在嵌入式项目里踩了几次坑,才真正搞明白这里面的门道。
今天咱们就把这块硬骨头啃下来。我会结合自己面试和被面试的经验,把经典题目掰开揉碎了讲。
一、内存对齐的核心规则
先复习一下对齐规则,就三条:
- 成员对齐:每个成员的起始地址,必须是它自身大小的整数倍
- 结构体对齐:整个结构体的大小,必须是最大成员大小的整数倍
- 编译器填充:不满足对齐时,编译器自动插入填充字节
记住一句话:对齐的本质是「用空间换时间」。CPU读对齐的数据,一次内存访问就够了;不对齐的话,可能要读两次再拼起来。
二、经典面试题:结构体大小计算
来看一道我面试时遇到的原题:
struct A {
char a; // 1字节
int b; // 4字节
short c; // 2字节
};
问:sizeof(struct A) 等于多少?
很多人脱口而出「1+4+2=7」。嗯,我当时也是这么答的。面试官笑了笑,说你再想想。
实际答案是 12。为什么?
咱们一步步推:
- char a 占偏移0,没问题
- int b 需要4字节对齐,当前偏移是1,不满足。编译器在a后面填充3个字节,b从偏移4开始
- short c 需要2字节对齐,当前偏移是8,满足。c占偏移8-9
- 结构体最大成员是int(4字节),总大小必须是4的倍数。目前用了10字节,填充到12
我的小技巧:画个格子图,把每个成员按对齐要求摆进去,空位就是填充字节。面试时在纸上画出来,比空想靠谱得多。
三、位域的陷阱
位域这东西,看着简单,用起来全是坑。我曾在通信协议解析的代码里,因为位域顺序搞反,排查了整整两天。
看这道笔试题:
struct BitField {
unsigned int a : 3; // 占3位
unsigned int b : 5; // 占5位
unsigned int c : 10; // 占10位
};
问:sizeof(struct BitField) 是多少?
关键点在于:位域成员不能跨存储单元。如果当前存储单元剩余位数不够放下下一个成员,编译器会另起一个存储单元。
假设unsigned int是4字节(32位):
- a占3位,b占5位,加起来8位,还在同一个32位单元里
- c需要10位,当前单元还剩24位,够用
- 总共用了18位,但结构体大小还是4字节
所以答案是 4。
注意:不同编译器对位域的分配顺序可能不同。有的从左到右,有的从右到左。跨平台代码里,千万别依赖位域的内存布局!
四、综合题:对齐+位域混合
这种题最考验功底。来看一道:
struct Mix {
char a; // 1字节
int b : 4; // 位域,4位
short c; // 2字节
double d; // 8字节
};
问:sizeof(struct Mix) 是多少?
咱们拆解一下:
- char a 占偏移0
- int b : 4 是位域,但它属于int类型,对齐要求按int(4字节)算。当前偏移1,需要填充到4,b从偏移4开始,占4位
- short c 需要2字节对齐。b只用了4位,但位域后面的空间不能跨类型使用。c从偏移6开始(因为b占4字节的存储单元,偏移4-7,c从偏移6开始)
- double d 需要8字节对齐。当前偏移8,满足。d占偏移8-15
- 最大成员是double(8字节),总大小16,已经是8的倍数
答案是 16。
避坑指南:位域的类型决定了它的对齐要求。int类型的位域,哪怕只占1位,也要按int对齐。我曾经在协议栈里用char类型定义位域,结果结构体大小比预期小了一半,排查了好久才发现是类型对齐的问题。
五、知识体系总览
下面这张图,把内存对齐和位域的核心知识点串起来了。面试前看一眼,心里就有底了。
六、常见笔试题速览
| 题目类型 | 考察点 | 常见陷阱 |
|---|---|---|
| 结构体大小计算 | 对齐规则、填充字节 | 忘记结构体整体对齐 |
| 位域大小计算 | 存储单元、位域类型 | 忽略类型对齐要求 |
| 混合场景 | 对齐+位域综合 | 位域跨存储单元 |
| #pragma pack | 强制对齐 | pack值小于成员大小 |
| offsetof宏 | 成员偏移量 | 位域成员不能用offsetof |
我的建议:面试前把这几类题各练5道,手写计算过程。别光看,一定要动手算。算完用sizeof验证,错了就复盘为什么。
说实话,内存对齐和位域这块,理解了规则就不难。难的是在真实项目中,你面对的是几百行的结构体定义,各种嵌套、位域、pack混在一起。那时候能快速定位问题,才是真本事。
嗯,今天就聊到这儿。这些题你拿回去练练,面试时遇到类似的,心里就有谱了。
公众号:蓝海资料掘金营,微信deep3321