假设我们有一个包含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*/
Run Code Online (Sandbox Code Playgroud)
小智 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;
};
Run Code Online (Sandbox Code Playgroud)
您可以使用网络功能存储/加载32位值:
INST i;
i.b = ntohl(value);
Run Code Online (Sandbox Code Playgroud)
现在,您可以在不进行类型转换的情况下引用位字段.
if (i.a.op_code == XXX)
Run Code Online (Sandbox Code Playgroud)
这是一个可行的答案,可移植,不会在任何编译器上调用未定义的行为,并且可以相当有效地优化:
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_;
};
Run Code Online (Sandbox Code Playgroud)
这使您可以使用非常方便的符号访问所有位字段。我认为它也是一个 POD,可以让您以一些有趣的方式使用它。一个好的编译器将在优化位修改操作方面做得相当不错,特别是当您连续多次调用便利函数时。
它几乎与具有覆盖位字段一样好。首先需要做更多的定义工作。
另外,我将类型更改为unsigned int,因为如果您正在摆弄这些位,您确实需要一个简单表示的数字,没有符号位或任何类似的时髦东西。理想情况下,您应该在顶部的 typedef 中包含<cstdint>标头和 using或某些内容。::std::uint32_t