基于位域的C结构体大小计算与指针差值疑问
位域结构体的内存布局疑问
测试代码
#include <stdio.h> struct test { unsigned int x; // 假设int为4字节 long int y : 33; // 假设long为8字节 unsigned int z; }; int main() { struct test t; unsigned int* ptr1 = &t.x; // long int* ptr3 = &t.y; unsigned int* ptr2 = &t.z; printf("sizeof(struct test) %lu\n", sizeof(struct test)); printf("&t.x %u\n", ptr1); printf("&t.z %u\n", ptr2); printf("ptr2 - ptr1 %ld\n", ptr2 - ptr1); return 0; }
实际输出结果
sizeof(struct test) 24 &t.x 3187370912 &t.z 3187370928 ptr2 - ptr1 4
疑问
我的预期为:
- 为x分配4字节
- 由于long int是位域类型,33位需占用8字节(仅使用33位)
- z分配4字节,因前8字节剩余空间不足4字节,无法复用
总大小应为16字节,但实际输出为24字节,这是如何计算的?
另外,位域的顺序会影响内存布局:x起始地址为3187370912,占用4字节;long int位域占用8字节;z应在x之后12字节处,指针差值(ptr2-ptr1)应为3,但实际输出为4,这是为什么?
解答
1. 结构体总大小为24字节的原因
C语言中位域的内存布局受类型对齐规则和存储单元分配规则共同约束,具体到这个结构体:
unsigned int x:占4字节,对齐要求为4字节,起始地址为结构体起始地址(3187370912),结束于3187370916。long int y : 33:位域的基础类型是long int(8字节),因此它的存储单元大小为8字节,同时必须满足long int的8字节对齐要求。而x的结束地址3187370916不是8的倍数,所以需要在x后填充4字节(地址31873709163187370920),让y的起始地址(3187370920)满足8字节对齐。y占用8字节的存储单元(31873709203187370928)来存放33位数据。unsigned int z:对齐要求为4字节,y的结束地址3187370928刚好满足4字节对齐,因此z从该地址开始,占用4字节(3187370928~3187370932)。- 结构体整体对齐要求:必须是最大成员对齐单元(这里是
long int的8字节)的整数倍。当前已用空间为4(x)+4(填充)+8(y)+4(z)=20字节,不是8的倍数,因此需要在z后再填充4字节,最终总大小为24字节。
2. 指针差值为4的原因
C语言中,同类型指针的差值是按元素个数计算的,而非字节数。ptr1是unsigned int*,指向x的起始地址3187370912;ptr2指向z的起始地址3187370928。两者的字节差为3187370928 - 3187370912 = 16字节,而每个unsigned int占4字节,因此元素个数差为16 / 4 = 4,这就是ptr2 - ptr1输出4的原因。
内容的提问来源于stack exchange,提问作者Pragati Bhattad
相关产品推荐
相关产品推荐

