H.Sean.N 2025-10-30 15:33 采纳率: 40%
浏览 5

关于位域定位的一些疑问;

我在编程调试中遇到以下问题,关于一个CAN帧,我定义了它的结构体:
方案1:

 struct {
        uint16_t  a      ;
        uint8_t   b       ;
        uint8_t   c       ;   
        uint32_t   over_current          :1;
        uint32_t  dcdc_output_overvolt    :1;
        uint32_t  over_temp_l2_a             :1;
        uint32_t  over_temp_l3_a             :1;
        uint32_t  k1k2_open_fault_a          :1;
        uint32_t  k1k2_adhesion_fault_a      :1;
        uint32_t  fuse_fault_a               :1;
        uint32_t  iso_fault_a                :1;
        uint32_t  iso_timeout_a              :1;
        uint32_t  output_volt_over_bcl_a     :1;
        uint32_t  output_current_over_bcl_a  :1;
        uint32_t  volt_mismatch_a            :1;
        uint32_t  dcdc_output_volt_over_a    :1;
        uint32_t  pem_a                      :1;
        uint32_t  pre_charge_timeout_a       :1;
        uint32_t  vehicle_volt_over_cml_a    :1;
        uint32_t  cp_offline_a               :1;
        uint32_t  output_volt_over_bcp_a     :1;
        uint32_t  volt_over60_before_iso_a   :1;
        uint32_t  secc_errcode_flag_a        :1;
        uint32_t                            :12; // 保留12位
    }
    memcpy(&ccu_can11[0], data, sizeof(ccu_can11_bsd_a_t));

然后执行函数,按位与。CAN发送帧00 00 00 00 01 00 00 00 ,没反应, 00 00 01 00 00 00 00 00
定位到40bit;和我希望的端序完全颠倒了,呆住。我希望的是00 00 00 00 01 00 00 00在32bit;尝试联合体:

方案2:

ypedef union {
    struct {
        uint64_t  a :16uint64_t b :8;
        uint64_t   c :8;
        uint64_t  ccu_over_current_a         :1;
        uint64_t  dcdc_output_overvolt_a     :1;
        uint64_t  over_temp_l2_a             :1;
        uint64_t  over_temp_l3_a             :1;
        uint64_t  k1k2_open_fault_a          :1;
        uint64_t  k1k2_adhesion_fault_a      :1;
        uint64_t  fuse_fault_a               :1;
        uint64_t  iso_fault_a                :1;
        uint64_t  iso_timeout_a              :1;
        uint64_t  output_volt_over_bcl_a     :1;
        uint64_t  output_current_over_bcl_a  :1;
        uint64_t  volt_mismatch_a            :1;
        uint64_t  dcdc_output_volt_over_a    :1;
        uint64_t  pem_a                      :1;
        uint64_t  pre_charge_timeout_a       :1;
        uint64_t  vehicle_volt_over_cml_a    :1;
        uint64_t  cp_offline_a               :1;
        uint64_t  output_volt_over_bcp_a     :1;
        uint64_t  volt_over60_before_iso_a   :1;
        uint64_t  secc_errcode_flag_a        :1;
        uint64_t                            :12; // 保留12位
    } bits; // 位域视图
    uint64_t fault_value; // 整数值视图
} ccu_can11_u; 

同上;丝毫没有好转;并且这次进一步发现,01 00 00 00 00 00 00 00
定位到32bit;阿巴阿巴了。

但是联合体这样使用:

方案3:


typedef union {
    struct {
        uint32_t  ccu_over_current_a         :1;
        uint32_t  dcdc_output_overvolt_a     :1;
        uint32_t  over_temp_l2_a             :1;
        uint32_t  over_temp_l3_a             :1;
        uint32_t  k1k2_open_fault_a          :1;
        uint32_t  k1k2_adhesion_fault_a      :1;
        uint32_t  fuse_fault_a               :1;
        uint32_t  iso_fault_a                :1;
        uint32_t  iso_timeout_a              :1;
        uint32_t  output_volt_over_bcl_a     :1;
        uint32_t  output_current_over_bcl_a  :1;
        uint32_t  volt_mismatch_a            :1;
        uint32_t  dcdc_output_volt_over_a    :1;
        uint32_t  pem_a                      :1;
        uint32_t  pre_charge_timeout_a       :1;
        uint32_t  vehicle_volt_over_cml_a    :1;
        uint32_t  cp_offline_a               :1;
        uint32_t  output_volt_over_bcp_a     :1;
        uint32_t  volt_over60_before_iso_a   :1;
        uint32_t  secc_errcode_flag_a        :1;
        uint32_t                            :12; // 保留12位
    } bits; // 位域视图
    uint32_t fault_value; // 整数值视图
} ccu_can11_u;

typedef struct {
    uint16_t   a          ;
    uint8_t      b            ;
    uint8_t   c      ;
    ccu_can11_u can11;
} ccu_can11_bsd_a_t;   

就可以定位到 00 00 00 00 01 00 00 00在32bit;我是试了这个后才去试2的方案的。然后 自己给自己整懵了。麻烦详细解释一下为什么? 我使用的是64位系统,为什么 u64没有按照小端序排列呢?如果按照小端序,我的第1,第2方案都应该正确才对,我定义了每一个位;
而且01 00 00 00 00 00 00 00对应到32是我万万没想到的。

咋都是deepseek,我想知道导致问题的原因,我也问过deepseek了。它只是总结分析,感觉最靠谱的说法是对齐或者填充导致的。

  • 写回答

5条回答 默认 最新

  • 阿里嘎多学长 2025-10-30 15:36
    关注

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    位域定位问题

    根据你的描述,你定义了一个结构体,包含两个成员变量:ab。但是,你可能遇到了位域定位的问题。

    在 C 语言中,位域是用来描述一个整数类型的某些位的含义的。位域的定义通常使用 structunion 来实现。

    方案1 的问题

    你的方案1 中,a 是一个 uint16_t 类型的变量,占用 16 位。b 是一个 uint8_t 类型的变量,占用 8 位。

    问题在于,b 的位域定位可能会与 a 的位域定位冲突。因为 a 占用了 16 位,b 占用了 8 位,可能会导致 b 的位域定位不正确。

    解决方案

    为了解决这个问题,你可以使用 struct 来定义位域,例如:

    struct {
        uint16_t  a      : 8;  // a 占用 8 位
        uint8_t   b       : 8;  // b 占用 8 位
    } can_frame;
    

    在这个例子中,ab 的位域定位都被明确指定了,避免了位域定位冲突的问题。

    注意

    在 C++ 中,位域的定义与 C 不同。C++ 使用 structclass 来定义位域,例如:

    struct {
        uint16_t  a      : 8;  // a 占用 8 位
        uint8_t   b       : 8;  // b 占用 8 位
    } can_frame;
    

    但是,C++ 中的位域定义可能会有不同的行为,例如,位域的顺序可能会影响其行为。因此,建议在 C++ 中避免使用位域。

    评论

报告相同问题?

问题事件

  • 修改了问题 10月30日
  • 创建了问题 10月30日