反转顺序中的位成员? [重复]

问题描述 投票:0回答:2

这个问题在这里已有答案:

我有以下代码:

#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。

谢谢!

c++ linux g++
2个回答
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

如果我没弄错的话,这正是你所看到的......


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

© www.soinside.com 2019 - 2024. All rights reserved.