我有以下代码:
#include <iostream>
#include <bitset>
#pragma pack(1)
typedef uint8_t flag_t;
typedef struct flag_struct_t {
flag_t f1:1;
flag_t f2:2;
flag_t f3:2;
flag_t f4:2;
flag_t f5:1;
} flag_struct_t;
int main() {
const uint8_t flagValue = 96;
std::bitset<8> mybits(flagValue);
const flag_struct_t flag = *reinterpret_cast<const flag_struct_t*>(&flagValue);
std::cout << "f2 = " << (uint16_t)flag.f2 << std::endl;
std::cout << "f3 = " << (uint16_t)flag.f3 << std::endl;
std::cout << "f4 = " << (uint16_t)flag.f4 << std::endl;
std::cout << "bitset = " << mybits << std::endl;
std::cout << "size of flag_struct_t = " << sizeof(flag_struct_t) << std::endl;
}
#pragma pack()
输出为:
$ ./mybitset
f2 = 0
f3 = 0
f4 = 3
bitset = 01100000
size of flag_struct_t = 1
似乎结构成员的顺序已从f1, f2, f3, f4
颠倒为f4, f3, f2, f1
。
那是为什么?
如果有问题,我正在使用GCC 8。
谢谢!
答案 0 :(得分:3)
首先,由于类型通过reinterpret_cast
修剪,您的程序具有未定义的行为。其次,位域的布局是实现定义的([class.bit]/1),因此不能保证位域的成员将如何开始分配。但是,现在让我们假设编译器会非常好,并且实际上将其转换为可以实现您期望的功能的代码。
十进制96的二进制表示形式为01100000。请注意,数字通常是从右到左书写的(大概是由于阿拉伯语的起源)。例如,十进制数字123中的“第一位”(最低有效位)应为3,而不是1。因此,如果我们假设编译器从第一位开始就按照声明的顺序打包了位域的成员,那么布局应该像这样
Bit 7 6 5 4 3 2 1 0
f5 f4 f4 f3 f3 f2 f2 f1
或者,对于您的示例中使用的特定值
Bit 7 6 5 4 3 2 1 0
0 1 1 0 0 0 0 0
如果我没记错的话,这正是您所看到的...
答案 1 :(得分:2)
const flag_struct_t flag = *reinterpret_cast<const flag_struct_t*>(&flagValue);
这种重新解释具有不确定的行为。
似乎结构成员的顺序已从
f1, f2, f3, f4
颠倒为f4, f3, f2, f1
。
您为什么期望订单是一个而不是另一个?位字段成员的顺序由实现定义。
GCC放置从“第一位”开始的位字段,即小字节序中的最低位和大字节序系统中的最高位:https://gcc.gnu.org/ml/gcc/2004-09/msg00581.html