#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检查,我得到的类型与类定义中声明的类型相同,但是在运行时似乎不是这样,因为当我尝试通过移位设置最后一位时,我得到一个负数。有任何想法吗?
来自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转移运营商
移位运算符<<和>>组从左到右。 ... 操作数应为整数或无范围的枚举类型,并执行整体促销。
typeid(c.x)
是uint32_t
,但是当使用<<
算子时,它被隐式转换为int
。
c.x
是0x1
。表达c.x << 31
是0x1 << 31
是0x80000000
(假设sizoef(int) == 4
和CHAR_BIT == 8
)。这个数字被解释为int
,并且在twos complement格式中它等于-2147483648
(INT_MIN
或std::intergral_limits<int>::min()
)。
请注意,由于有符号整数溢出,当前表达式c.x << 31
(C ++ 17)会调用未定义的行为。
那么在类定义中声明的类型有什么意义呢?
填充。一些编译器将不同类型的位域解释为“填充分隔符”(不知道如何命名)。如果结构中的下一个成员具有与前一个成员不同的类型(都是位域),那么我希望编译器将第二个成员从新的“新”字节开始。我希望c.x
和c.y
之间有比特填充,因为它们有不同的类型。如果它是struct C { uint32_t y : 2; uint32_t x : 2; }
那么编译器更有可能将它们放在同一个字节中。请参阅编译器文档或other resources。