结构体强制转换后8字节变量仅占4字节的原因排查
问题描述
定义如下结构体:
struct ggg { unsigned long long int a; unsigned int b; };
其中字段a预期为8字节,字段b为4字节。尝试将字节数组强制转换为该结构体类型:
unsigned char c[8 + 4] = { 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, }; ggg* g = (ggg *)c ; char tt[1024]; sprintf(tt, "a=%d b=%d ", g->a, g->b);
最终tt字符串的结果为:
a=1 b=2
看起来强制转换后a仅占用了4字节而非预期的8字节,请问这是什么原因?
问题原因分析
出现该问题的核心原因有两点:
1. 结构体内存对齐与非法指针转换
C语言中,结构体成员遵循内存对齐规则——为提升CPU访问效率,编译器会在成员间插入填充字节,同时要求结构体起始地址满足最大成员的对齐要求。
对于struct ggg:
unsigned long long int a是8字节,要求起始地址对齐到8字节边界;unsigned char数组c没有对齐要求,其起始地址大概率不满足8字节对齐条件。
直接将无对齐的数组指针强制转换为结构体指针属于未定义行为,CPU读取a时会因地址不对齐出现异常,导致a只读取了前4字节,后续4字节被错误识别为b的内容。
2. 格式符与类型不匹配
你用%d打印unsigned long long int类型的a,这是错误的。%d对应int类型(通常4字节),传入8字节的unsigned long long会触发数据截断,进一步加剧结果异常。正确格式符应为%llu(无符号长整型)。
验证与解决建议
- 查看结构体实际大小:用
sizeof(struct ggg)会发现结果是16字节(8字节a+ 4字节b+ 4字节填充),而非预期的12字节; - 避免强制转换无对齐数组:改用
memcpy将数组内容拷贝到结构体变量,保证内存对齐; - 使用匹配的格式符:
unsigned long long用%llu,unsigned int用%u。
修改后的示例代码:
#include <string.h> #include <stdio.h> struct ggg { unsigned long long int a; unsigned int b; }; int main() { // 预留结构体实际大小的空间,包含填充字节 unsigned char c[16] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00 }; struct ggg g; memcpy(&g, c, sizeof(g)); char tt[1024]; sprintf(tt, "a=%llu b=%u ", g.a, g.b); printf("%s\n", tt); return 0; }
内容的提问来源于stack exchange,提问作者vico
相关产品推荐
相关产品推荐

