返回对位字段的访问类型

return type of access to bitfield

本文关键字:访问类型 字段 返回      更新时间:2023-10-16
#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 位位域成员。根据类型特征检查,我得到了与类定义中声明的相同的类型,但是在运行时似乎并非如此,因为当我尝试通过移位设置最后一位时,我得到一个负数。有什么想法吗?

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

7.3.6 积分促销

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

从C++草案 2019-04-12 expr.shift 7.6.7p1:

7.6.7 移位运算符

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

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

c.x0x1.表达式c.x << 310x1 << 310x80000000(假设sizoef(int) == 4CHAR_BIT == 8)。这个数字被解释为一个int,在二进制补码格式中,它等于-2147483648(INT_MIN或那个std::intergral_limits<int>::min())。

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

此外,在类定义中声明的类型有什么意义呢?

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