C语言如何打包数组中的结构体并消除零填充?
位域结构体数组无填充打包方案说明
问题根源
你遇到的现象是C语言的标准特性导致的:
- 即使添加了
__attribute__((packed))属性,结构体的最小占用大小始终为1字节,小于1字节的位域组合会被填充到1字节对齐 - 数组元素之间确实不存在填充,但因为你的单个
data_struct大小已经是1字节,所以数组每个元素占1字节,4个元素总大小为4字节,你拿到的0x0F0F就是前两个元素的低4位有效、高4位填0的结果
注意:位域的内存布局和编译器、CPU端序强相关,如果需要跨平台兼容的打包格式,建议优先使用手动位操作的方案2,稳定性更高。
可行解决方案
方案1:固定数量元素打包(适配你当前需要4个元素凑16位的场景)
直接把4组位域合并到同一个结构体中,就可以消除结构体之间的填充,代码示例:
#include <stdio.h> #include <stdint.h> #include <string.h> int main() { // 把4组4位的位域放在同一个结构体里,总大小刚好16位 struct packed_4elem { unsigned a0:1; unsigned b0:3; unsigned a1:1; unsigned b1:3; unsigned a2:1; unsigned b2:3; unsigned a3:1; unsigned b3:3; } __attribute__((packed)); union { struct packed_4elem data; uint16_t data_uint; } union_data; memset(&union_data.data_uint, 0, sizeof(union_data.data_uint)); // 批量赋值 union_data.data.a0 = 1; union_data.data.b0 =7; union_data.data.a1 = 1; union_data.data.b1 =7; union_data.data.a2 = 1; union_data.data.b2 =7; union_data.data.a3 = 1; union_data.data.b3 =7; printf("union_data = 0x%04X\n", union_data.data_uint); // 输出为0xFFFF return 0; }
方案2:变长数组手动位操作(适配任意长度的4位元素场景)
如果需要使用更长的、元素数量不固定的4位元素数组,直接用字节数组存储,手动封装位读写逻辑即可,不需要用结构体:
// 读取第n个元素的a字段 #define GET_A(buf, n) (((buf)[(n)/2] >> (4*((n)%2))) & 0x1) // 读取第n个元素的b字段 #define GET_B(buf, n) (((buf)[(n)/2] >> (4*((n)%2) + 1)) & 0x7) // 写入第n个元素的a和b字段 #define SET_AB(buf, n, a, b) do { \ (buf)[(n)/2] &= ~(0xF << (4*((n)%2))); \ (buf)[(n)/2] |= (((a) & 0x1) | ((b & 0x7) << 1)) << (4*((n)%2)); \ } while(0)
内容的提问来源于stack exchange,提问作者HennyKo
相关产品推荐
相关产品推荐

