结构体填充理解困惑:结构体成员地址与指针运算疑问
结构体内存布局与指针运算疑问解答
实验代码
#include <stdio.h> int main(int argc, char **argv) { struct a_t { char aa; }; struct b_t { int bb; int bbb; }; struct c_t { struct a_t parent_a; struct b_t parent_b; char cc; }; struct c_t c; printf("sizeof(a_t)=%d\n", sizeof(struct a_t)); printf("sizeof(b_t)=%d\n", sizeof(struct b_t)); printf("c address=%p\n", &c); printf("c's parent_a=%p\n", &(c.parent_a)); printf("c's parent_b=%p\n", &(c.parent_b)); printf("c + sizeof(a_t)=%p\n", (struct b_t *)(&c + sizeof(struct a_t))); return 0; }
输出结果
sizeof(a_t)=1 sizeof(b_t)=8 c address=0x7fff9bca7680 c's parent_a=0x7fff9bca7680 c's parent_b=0x7fff9bca7684 c + sizeof(a_t)=0x7fff9bca7690
疑问与解答
疑问2:parent_b的地址为0x7fff9bca7684,并非8的倍数,而parent_b大小为8字节,对此感到疑惑
结构体的对齐核心规则是:成员的起始地址必须对齐到该成员类型对齐要求的整数倍,而结构体的对齐要求由其内部最大的基础数据类型成员决定。
struct b_t的成员是两个int(通常占4字节),因此b_t的对齐要求是4字节,而非8字节。parent_a占1字节,为了满足parent_b的4字节对齐要求,编译器会在parent_a后填充3字节,因此parent_b的起始地址为0x7fff9bca7680 + 1 + 3 = 0x7fff9bca7684,刚好是4的倍数,完全符合对齐规则。sizeof(b_t)=8是因为两个int各占4字节,总大小刚好是对齐后的结果,和对齐要求本身无关。
疑问3:&c + sizeof(struct a_t)的结果为0x7fff9bca7690,超出c的地址16字节,而struct a_t大小仅为1字节,与预期不符
这是对C语言指针运算规则的误解:指针加法的偏移量是「加数 × 指针指向类型的大小」,而非直接累加字节数。
&c是struct c_t*类型,sizeof(struct c_t)的计算结果是16字节(布局:1字节parent_a+ 3字节填充 + 8字节parent_b+ 1字节cc+ 7字节填充,总大小对齐到结构体的对齐边界)。sizeof(struct a_t)=1,因此&c + sizeof(struct a_t)等价于&c + 1,按照指针运算规则,实际偏移量是1 × sizeof(struct c_t) = 16字节,所以结果是0x7fff9bca7680 +16 = 0x7fff9bca7690。- 如果想实现「从&c的地址偏移1字节」的效果,需要先将指针转换为
char*类型再做加法:(struct b_t*)((char*)&c + sizeof(struct a_t)),这样结果才会符合你的预期。
内容的提问来源于stack exchange,提问作者my_question
相关产品推荐
相关产品推荐

