C/C++:uint8_t位域的行为不正确且不一致
C/C++: uint8_t bitfields behave incorrectly and inconsistently
我有以下代码:
struct Foo {
uint16_t a:5;
uint16_t b:5;
uint16_t c:5;
};
uint16_t bits = 0xdae;
const Foo& foo = *reinterpret_cast<const Foo*>(&bits);
printf("%x %x %xn", foo.a, foo.b, foo.c);
输出是我在纸上计算时所期望的:
E D 3
如果我使用 uint32_t 而不是 uint16_t 位域,我会得到相同的结果。
但是当我使用 uint8_t 位域而不是 uint16_t 时,我得到的结果不一致,即:
E d 6
或
E d 16
两者都不正确。为什么将uint8_t用于位域会导致这种奇怪的行为?
编译器可能会在结构成员之间添加填充(或者它可能不会,由其判断),当您只是尝试将整个结构作为一堆位访问时,您不会考虑这一点。基本上你不能只是这样做(行为是未定义的,你的代码只是有问题)。您需要按名称访问结构成员或使用特定于编译器的扩展来控制布局/填充。
位字段的内存布局是实现定义的。例如,授予以下在线 c++ 标准草案:
9.6 位字段
(1) ...类对象中位字段的分配为 实现定义。位字段的对齐方式为 实现定义。
因此,由于您不会通过长度为 0 的位字段引入显式填充,因此您无法控制编译器在内存中如何布局结构。实际上,我认为您会产生未定义的行为,因为您将一个指针转换为另一个指针,可能具有不同的对齐要求,并且访问填充位(就像分配重新解释的强制转换时发生的那样)也是未定义的行为。
请注意,您可以通过标准化方式控制位字段的填充:
(2) 省略标识符的位字段声明声明 未命名的位域。未命名的位字段不是成员,不能 初始 化。[注意:未命名的位字段对于填充到 符合外部强加的布局。— 尾注 ] 作为特例, 宽度为零的未命名位字段指定 分配单元边界处的下一个位字段。仅当声明 未命名的位字段 常量表达式的值可能等于 零。
请参阅以下使用此功能的代码;请注意,它会产生不同的结果,因为我发现无法控制填充,以便我可以获得连续的 5 位馅饼。因此,我将示例改编为适用于字节边框级别的内容:
struct Foo {
uint8_t a:5;
uint8_t :0;
uint8_t b:5;
uint8_t :0;
uint8_t c:5;
};
union DifferentView {
uint32_t bits;
struct Foo foo;
};
int main()
{
union DifferentView myView;
myView.bits = 0x0d0a0e;
printf("%x %x %xn", myView.foo.a, myView.foo.b, myView.foo.c);
// Output: e a d
return 0;
}
- 使用2个键的cpp-stl::优先级队列排序不正确
- 正弦级数方程计算不正确
- 我试图制作一个程序,要求用户输入问题和答案,但程序循环不正确
- 密码登录程序将永远循环并显示不正确的结果
- 在C++中返回不正确的楼层函数值
- 形状对象的旋转和缩放不正确C++
- C++ 读取文件读取文件不正确
- 关于类的 Python 文档 - 对C++的引用不正确
- 特征 LLT 模块给出不正确的结果?
- glibcxx STL 在实现 std::valarray::sum() 时是否不正确?
- 如果语句逻辑不正确
- 来自逆 vp 矩阵和相机位置的光线方向不正确
- 不正确的操作数类型 MSVC
- 数组填充了不正确的值
- 我是否不正确地集中了这些字符数组?
- 为什么除非我使用 cout,否则我的值不正确?
- 计算幂级数的数学结果不正确
- 为什么 sizeof 在 C++ 中给出不正确的字节数?
- atoi() 在应用于大型命令行参数时会产生不正确的值
- C/C++:uint8_t位域的行为不正确且不一致