假设我们有一个包含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*/
答案 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
或其他内容。