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