在C ++中切割位

时间:2011-12-02 22:23:20

标签: c++ c

假设我们有一个包含32位数字的二进制文件。每个32位数字代表一条指令。我的问题:是否可以直接将这些位切成6 + 5 + 5 + 16的块。类似的东西:

typedef struct _instruction
{
    int op_code : 6;
    int reg_dest : 5;
    int reg_s1 : 5;
    int offset : 16;
} INST, *PINST;

int read_32_bits = read_next_instr();

INST i = (INST)read_32_bit; /* this would cut the bits into chunks*/

3 个答案:

答案 0 :(得分:6)

为什么不像你一样创建一个比特结构,然后把它放在一个联盟里呢?我删除了typedef,因此它使用了C ++样式定义。

struct instruction
{
    int op_code  : 6;
    int reg_dest : 5;
    int reg_s1   : 5;
    int offset   :16;
};

union INST
{
    instruction  a;
    uint32_t     b;
};

您可以使用网络功能存储/加载32位值:

INST  i;
i.b = ntohl(value);

现在你可以在没有类型转换的情况下引用位字段。

if (i.a.op_code == XXX)

答案 1 :(得分:4)

您可以将结构转换为指向32位数据地址的指针。

INST* i = (INST*)&read_32_bit;

然后您可以访问您的字段,如下所示:

printf("opcode = %x", i->op_code);

答案 2 :(得分:3)

这是一个可行的解决方案,可移植,不会在任何编译器上调用未定义的行为,并且可以相当有效地进行优化:

struct instruction {
   typedef unsigned int uint_t;

   explicit instruction(uint_t val) : val_(val) {}
   instruction(uint_t op_code, uint_t reg_dest, uint_t reg_s1, uint_t offset)
     : val_((op_code & 0x3fu << 26) | (reg_dest & 0x1fu << 21) |
            (reg_s1 & 0x1fu << 16) | (offset & 0xffffu))
   {
   }

   uint_t op_code() const { return (val_ >> 26) & 0x3fu; }
   void op_code(uint_t newval) { val_ = (newval & 0x3fu << 26) | (val_ & 0x3ffffffu); }

   uint_t reg_dest() const { return (val_ >> 21) & 0x1fu; }
   void reg_dest(uint_t newval) { val_ = (newval & 0x1fu << 21) | (val_ & 0xfc1fffffu); }

   uint_t reg_s1() const { return (val_ >> 16) & 0x1fu; }
   void reg_s1(uint_t newval) { val_ = (newval & 0x1fu) << 16) | (val_ & 0xffe0ffffu); }

   uint_t offset() const { return (val_ >> 16) & 0xffffu; }
   void offset(uint_t newval) const { val_ = (newval & 0xffffu) | (val & 0xffff0000u); }

   uint_t &int_ref() { return val_; }
   uint_t int_ref() const { return val_; }

 private:
   uint_t val_;
};

这使您可以使用非常方便的表示法访问所有位域。我认为这也是一个POD,它允许你以一些有趣的方式使用它。一个好的编译器可以在优化位整理操作方面做得相当不错,特别是如果你连续多次调用便捷函数的话。

它几乎和覆盖位字段一样好。首先要定义一些工作。

另外,我将类型更改为unsigned int,因为如果你正在摆弄这些位,你真的想要一个简单代表的数字,没有符号位或类似的任何时髦。理想情况下,您要包含<cstdint>标题,并在顶部的typedef中使用::std::uint32_t或其他内容。