返回对位域的访问类型

问题描述 投票:1回答:1
#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++ bit-fields
1个回答
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转移运营商

移位运算符<<和>>组从左到右。 ... 操作数应为整数或无范围的枚举类型,并执行整体促销。

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

© www.soinside.com 2019 - 2024. All rights reserved.