【问题标题】:How can I concatenate integer bit fields in c into a uint64_t integer?如何将 c 中的整数位字段连接成 uint64_t 整数?
【发布时间】:2020-03-18 10:05:38
【问题描述】:

我在 c 中有一个这样的结构

struct RegisterStruct
{
    uint64_t b_0 : 64;
    uint64_t b_1 : 64;
    uint64_t c_0 : 64;
    uint64_t c_1 : 64;
    uint64_t c_2 : 64;
    uint64_t d_0 : 64;
    uint64_t d_1 : 64;
};

我想将这些字段连接成一个uint64_t 整数。每个字段应占用给定的位数,定义如下:

b_0: 4bits 
b_1: 4bits
c_0: 8bits
c_1: 8bits
c_2: 8bits
d_1: 16bits
d_2: 16bits

结果应该是一个uint64_t 整数,其中包含连接的位字段(从b_0d_2),每个位字段占用给定的位数。

这是我尝试过的,但我认为这个解决方案不正确:

struct RegisterStruct Register;

   Register.b_0 = 8;
   Register.b_1 = 8;
   Register.c_0 = 128;
   Register.c_1 = 128;
   Register.c_2 = 128;
   Register.d_0 = 32768;
   Register.d_1 = 32768;

   uint64_t reg_frame =Register.b_0<<60|Register.b_1<<56|Register.c_0<<48|Register.c_1<<40|Register.c_2<<32|Register.d_0<<16|Register.d_1;

【问题讨论】:

  • "...但我认为这个解决方案不正确" 为什么它不正确?你遇到了什么问题?
  • 在您发布的struct RegisterStruct 中,所有位域宽度均为64。这是剪切和粘贴错误吗?您确定要它们为 4、4、8、8、8、16 和 16?
  • 您的解决方案是正确的。我自然会从最低有效位理解位顺序,所以我会将b_0: 4bits 作为最低有效位。
  • 如果您移动位域,请将它们转换为足够宽度的无符号整数类型,即使声明它们的基类型是这样的类型。作为we have seen recently,C 标准不清楚位域的实际类型是什么,因此uint64_t x : 4 可能像(例如)表达式中的32 位int,然后是Register.x &lt;&lt; 60将有一个超出int 界限的移位量并且具有C 标准未定义的行为。
  • @Kinyugo 我看不出将所有位域设为 64 位宽的意义。它们将(可能)与非位字段 uint64_t 成员的行为相同。

标签: c bit-manipulation bit bit-shift


【解决方案1】:

您可以将包含位字段的结构与完整的 64 位无符号整数放在一个联合中,如下所示:

union RegisterUnion
    struct
    {
        uint64_t b_0 : 4;
        uint64_t b_1 : 4;
        uint64_t c_0 : 8;
        uint64_t c_1 : 8;
        uint64_t c_2 : 8;
        uint64_t d_0 : 16;
        uint64_t d_1 : 16;
    };
    uint64_t val;
};

上面的主要问题是它不便携。 C 标准将位字段打包到其底层存储单元类型(在本例中为uint64_t)的顺序保留为实现定义的决定。这与多字节整数中的字节顺序完全不同,即小端字节序与大端字节序。

此外,可能不支持使用uint64_t 作为位字段的基本类型。仅需要实现支持_Boolsigned intunsigned int(或其合格版本)类型的位字段成员。根据C11 draft 6.7.2.1 paragraph 5

  1. 位字段的类型应为_Boolsigned intunsigned int 或其他一些实现定义的类型的合格或非合格版本。是否允许原子类型由实现定义。

【讨论】:

    【解决方案2】:
    typedef union
    { 
        struct
        {
            uint64_t b_0 : 4;
            uint64_t b_1 : 4;
            uint64_t c_0 : 8;
            uint64_t c_1 : 8;
            uint64_t c_2 : 8;
            uint64_t d_0 : 16;
            uint64_t d_1 : 16;
        };
        uint64_t u64;
    }R_t;
    
    
    int main()
    {
    
        R_t Register;
    
        Register.b_0 = 8;
        Register.b_1 = 8;
        Register.c_0 = 128;
        Register.c_1 = 128;
        Register.c_2 = 128;
        Register.d_0 = 32768;
        Register.d_1 = 32768;
    
        printf("%llx\n", (long long unsigned)Register.u64);
    }
    

    https://godbolt.org/z/_dYuz2

    【讨论】:

      猜你喜欢
      • 2015-01-28
      • 2013-12-12
      • 2016-11-24
      • 2023-02-09
      • 1970-01-01
      • 1970-01-01
      • 2017-12-01
      • 2023-04-02
      • 1970-01-01
      相关资源
      最近更新 更多