关于C#:位成员以相反的顺序?

Bit Members in Reversed Order?

本问题已经有最佳答案,请猛点这里访问。

我有以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#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()

输出为:

1
2
3
4
5
6
$ ./mybitset
f2 = 0
f3 = 0
f4 = 3
bitset = 01100000
size of flag_struct_t = 1

似乎结构成员的顺序已从f1, f2, f3, f4反转为f4, f3, f2, f1

那是为什么?

如果需要的话,我正在使用GCC8。

谢谢!


首先,由于类型通过reinterpret_cast修剪,您的程序具有未定义的行为。其次,位域的布局是实现定义的([class.bit] / 1),因此无法保证位域的成员将如何开始分配。但是现在让我们假设编译器会非常好,并且实际上将其转换为可以实现您期望的功能的代码。

十进制96的二进制表示形式为01100000。请注意,数字通常从右到左书写(大概是由于阿拉伯语的起源)。例如,十进制数字123中的"第一位"(最低有效位)应为3,而不是1。二进制没有什么不同。因此,如果我们假设编译器从第一位开始就按照声明的顺序打包了位域的成员,则布局应如下所示:

1
2
Bit  7  6  5  4  3  2  1  0  
    f5 f4 f4 f3 f3 f2 f2 f1

或者,对于示例中使用的特定值

1
2
Bit  7  6  5  4  3  2  1  0  
     0  1  1  0  0  0  0  0

这就是您所看到的,如果我没记错的话...


1
const flag_struct_t flag = *reinterpret_cast<const flag_struct_t*>(&flagValue);

此重新解释具有不确定的行为。

It seems like the order of struct members has been reversed from f1, f2, f3, f4 to f4, f3, f2, f1.

您为什么期望订单是一个订单而不是另一个订单?位字段成员的顺序由实现定义。

GCC放置从"第一位"开始的位字段,即小端序的最低位和大端序系统的最高位:https://gcc.gnu.org/ml/gcc/2004-09/msg00581.html