返回对位字段的访问类型
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 位位域成员。根据类型特征检查,我得到了与类定义中声明的相同的类型,但是在运行时似乎并非如此,因为当我尝试通过移位设置最后一位时,我得到一个负数。有什么想法吗?
来自 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.x
是0x1
.表达式c.x << 31
是0x1 << 31
是0x80000000
(假设sizoef(int) == 4
和CHAR_BIT == 8
)。这个数字被解释为一个int
,在二进制补码格式中,它等于-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; }
,那么编译器更有可能将它们放在同一个字节中。请参阅编译器文档或其他资源。
- 将结构字段的类型展开为可变模板参数
- 链接器找不到在虚拟类 c++ 中访问的静态字段的符号
- 结构体和类的不同大小(),彼此具有相同的字段类型
- 错误:字段'dateOfBirth'的类型不完整'Poco::Data::Date'
- 获取具有字段名称的 SELECT 字段类型,并带有 MariaDB C++连接器
- 无法访问 Arduino 结构字段。错误"退出状态 1。xxxx 不命名类型"
- 从一个类访问私有字段到另一个与C++中的前一个类无关的私有字段 (OOP)
- 访问向量字段的键 - 枚举类还是命名空间中的枚举?
- 返回对位字段的访问类型
- 在大型C/C 项目中访问现有字段
- 如何有效地从该对象中包含的另一个对象访问对象字段/属性
- 好友功能 - 无法访问私人字段C++
- C++ exc_bad_access从unordered_map中指向的对象访问字符串字段
- 使用decltype访问静态字段
- 在std::set/std::map中存储具有多个不同类型字段的c++对象的有效方法
- 从另一个类中访问类字段的语法
- Python-ctypes-如何调用函数和访问结构字段
- 为什么不应该直接访问__m128i字段
- 在 c++ 中访问类中的字段和类型列表
- 如何在多线程环境下安全地访问结构字段