C结构体sizeof与Python struct.calcsize结果不一致问题咨询
结构体大小不匹配问题
定义的C结构体
typedef struct { double cycle_time; double cycle_duty; double state; double servo_mode; double motion_mode; double jcond; struct { uint16_t buff_sz; uint16_t buff_fill; uint16_t cmd_cntr; uint16_t res; } wpi; double move_des_q[6]; double move_des_qd[6]; double move_des_x[6]; double move_des_xd[6]; double act_q[6]; double act_qd[6]; double act_x[6]; double act_xd[6]; double act_tq[6]; double frict_tq[6]; double ne_tq[6]; double act_force_e[6]; double act_force_0[6]; double des_trq[6]; double des_qd[6]; double temp_m[6]; double temp_e[6]; double arm_current; double arm_voltage; double psu_voltage; struct { uint8_t dig_in_count; uint8_t an_in_count; uint8_t dig_in[8]; uint8_t an_in_curr_mode[4]; double an_in_value[4]; uint8_t dig_out_count; //number of bits uint8_t an_out_count; uint8_t dig_out[8]; uint8_t an_out_curr_mode[4]; double an_out_value[4]; } io; struct { uint32_t jointState; float joint_volt; float joint_amp; uint8_t joint_window; float joint_des_iq; float joint_des_vel; } jointInfo[6]; } some_structure;
C语言计算结构体大小
int main() { printf("Size of struct ABC: %lu\n", sizeof(some_structure)); }
运行结果为1136字节。
Python使用struct模块计算
import struct struct_string = "<6d4H105d14B4d14B4dL2fB2fL2fB2fL2fB2fL2fB2fL2fB2fL2fB2f" struct_byte_size = struct.calcsize(struct_string) print(struct_byte_size)
运行结果为1114字节。
疑问
- 该大小差异产生的原因是什么?
- 如何通过Socket接收数据时避免该差异?
- 我的struct字符串是否存在错误?
问题解答
1. 大小差异的原因
核心原因是C语言的结构体内存对齐机制,而Python的struct模块默认只会按格式字符串指定的类型大小累加,不会自动添加对齐填充字节。
具体来说:
- C编译器为提升内存访问效率,会对结构体成员做对齐处理。比如
double通常要求8字节对齐,uint32_t要求4字节对齐。当结构体中较小类型(如uint8_t、uint16_t)后面跟着较大类型时,编译器会自动插入填充字节,保证后续成员的起始地址符合对齐要求。 - 你的Python格式字符串只是简单罗列类型字节数,没考虑这些填充字节,所以计算出的总大小比C的结果少了22字节(1136-1114),这些缺失的部分就是C编译器添加的对齐填充。
举个实际例子:
io结构体中,an_in_curr_mode[4]是4个uint8_t(共4字节),后面跟着double an_in_value[4],double需要8字节对齐,编译器会插入4字节填充;jointInfo的每个子结构体里,uint8_t joint_window后面跟着float(4字节),需要插入3字节填充保证对齐,6个这样的子结构体就会产生18字节填充;- 加上其他位置的填充,总和就是22字节的差异。
2. Socket接收数据时避免差异的方法
有两种可靠方案:
方案一:修改C代码,禁用结构体对齐
在定义结构体时添加编译器指令强制取消对齐。GCC用__attribute__((packed)),MSVC用#pragma pack:// GCC示例 typedef struct __attribute__((packed)) { // 结构体成员... } some_structure; // MSVC示例 #pragma pack(push, 1) typedef struct { // 结构体成员... } some_structure; #pragma pack(pop)这样C结构体大小会和Python
struct计算的一致,Socket传输时直接按字节流收发即可。方案二:在Python格式字符串中手动添加填充字节
分析C结构体的对齐规则,在Python格式字符串对应位置插入填充字节(用x表示)。比如:- 在
io结构体的an_in_curr_mode[4]之后添加4x(4字节填充); - 在每个
jointInfo子结构体的uint8_t joint_window之后添加3x(3字节填充),6个就是(L2fB3x2f)重复6次; - 检查所有可能的填充位置,把填充字节都加到格式字符串中,计算出的大小就会和C的1136字节一致。
- 在
3. 你的struct字符串是否存在错误?
是的,存在多处错误:
- 类型计数错误:你写的
105d完全不符合实际。数一下结构体中的double成员:前6个独立double+ 14个长度为6的double数组(14*6=84) + 后面3个独立double+io里的8个double,总共是6+84+3+8=101个double,不是105个。 jointInfo格式错误:每个jointInfo子结构体的类型是uint32_t(对应L)、2个float(f)、uint8_t(B)、2个float(f),但你重复写了多次L2fB2f,且没考虑填充字节。正确的单个jointInfo格式应该是L2fB3x2f(加上3字节填充)。- 整体结构混乱:前面的
105d错误导致后续格式的对应关系完全错位,虽然io部分的14B4d14B4d计数正确,但整体格式已经失效。
内容的提问来源于stack exchange,提问作者Mika
相关产品推荐
相关产品推荐

