返回对位域的访问类型

时间:2019-04-23 08:15:38

标签: c++ bit-fields

#include <iostream>
#include <type_traits>

struct C
{
    uint32_t x : 2;
    bool y : 2;
};

int main()
{
    C c{0b1};

    std::cout << (static_cast<uint32_t>(0b1) << 31) << std::endl;
    std::cout << (c.x << 31) << std::endl;
    std::cout << (c.x << 10) << std::endl;
    std::cout << std::boolalpha << std::is_same_v<decltype(c.x), uint32_t> << std::endl;
    std::cout << std::boolalpha << std::is_same_v<decltype(c.y), bool> << std::endl;
}

编译

g++ -g  test.cpp -std=c++17

g++ (GCC) 8.2.0

输出

2147483648
-2147483648
1024
true
true

我的问题是关于表达式c.x的类型,其中x是2位位域成员。根据typetraits检查,我得到与类定义中声明的类型相同的类型,但是似乎在运行时不正确,因为当我尝试通过移位设置最后一位时,我得到一个负数。有什么想法吗?

1 个答案:

答案 0 :(得分:3)

来自C++draft 2019-04-12 conv.prom 7.3.6p5

  

7.3.6整体促销

     

如果int可以表示位字段的所有值,则可以将整数位字段([class.bit])的prvalue转换为int类型的prvalue;

来自C++draft 2019-04-12 expr.shift 7.6.7p1

  

7.6.7 Shift运算符

     

移位运算符<<和>>从左到右分组。
   ...
  操作数应为整数或无作用域枚举类型,并执行整数提升。

typeid(c.x)uint32_t,但是使用<<运算符时,它会隐式转换为int

c.x0x1。表达式c.x << 310x1 << 310x80000000(假设sizoef(int) == 4CHAR_BIT == 8)。此数字被解释为int,并以twos complement格式等于-2147483648INT_MINstd::intergral_limits<int>::min())。

请注意,由于有符号整数溢出,表达式c.x << 31当前(C ++ 17)调用未定义的行为。

  

那么,在类定义中声明的类型的意义是什么?

填充。一些编译器将不同类型的位域解释为“填充分隔符”(不知道如何命名)。如果结构中的下一个成员的类型不同于前一个(都是位域),则我希望编译器将第二个成员从新的“新”字节开始。我希望c.xc.y之间会有一些填充,因为它们的类型不同。如果为struct C { uint32_t y : 2; uint32_t x : 2; },则编译器更有可能将它们放在同一字节中。请参阅您的编译器文档或other resources