You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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字节。

疑问

  1. 该大小差异产生的原因是什么?
  2. 如何通过Socket接收数据时避免该差异?
  3. 我的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结构体大小会和Pythonstruct计算的一致,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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 16:44:50