return 位域访问类型

return type of access to bitfield

#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 检查,我得到的类型与 class 定义中声明的类型相同,但是在运行时这似乎不是真的,因为当我尝试通过移位设置最后一位时,我得到了一个负数。有什么想法吗?

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

7.3.6 Integral promotions

A prvalue for an integral bit-field ([class.bit]) can be converted to a prvalue of type int if int can represent all the values of the bit-field;

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

7.6.7 Shift operators

The shift operators << and >> group left-to-right.
...
The operands shall be of integral or unscoped enumeration type and integral promotions are performed.

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) 由于有符号整数溢出而调用未定义的行为。

Moreover what is the significance of the type declared in the class definition then?

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