将位字段封装得更加紧密
Packing bitfields even more tightly
派生类中的位字段有问题。
使用g++编译器,您可以将__attribute__((packed))
分配给一个类,它将打包位字段。所以
class A
{
public:
int one:10;
int two:10;
int three:10;
} __attribute__ ((__packed__));
仅占用4个字节。到目前为止,一切都很好
但是,如果你继承了一个类,比如这个
class B
{
public:
int one:10;
int two:10;
} __attribute__ ((__packed__));
class C : public B
{
public:
int three:10;
} __attribute__ ((__packed__));
我希望与上面的类A具有相同内容的类C也具有相同的布局,即占用4个字节。然而,C占用了5个字节。
所以我的问题是,我做错了什么吗?如果是,怎么办?或者这是编译器的问题?一个疏忽,一个真正的错误?
我试过在谷歌上搜索,但除了Linux和Windows(编译器试图模仿MSVC)之间的区别之外,我什么都没想出来,我对此不感兴趣。这只是在Linux上。
我认为问题出在B上,它不可能是2.5字节。它必须至少为3个字节。
理论上,派生类可能被允许重用基类中的填充,但我从未见过这种情况发生。
想象一下,您所要求的是可能的。这可能会产生什么副作用或问题?让我们看看你的一个具体例子。还假设一个具有1字节内存对齐的32位体系结构。
class A
中有20个连续的位,您可以通过类的成员one
和two
进行寻址。这对你来说是一个非常方便的称呼,人类。但是编译器是怎么做到的呢?它使用掩码并将位移位到位置,将这些位移到正确的位置。
到目前为止,一切都很好,似乎足够简单和安全。
再添加10位。比方说,有一个非常聪明的编译器,它可以让你把多余的10位压缩到一个已经使用过的32位单词中(它们非常适合,不是吗?)。
麻烦来了:
A* derived = new B; // upcast to base class
derived->one = 1;
derived->two = 2;
// what is the value of derived->three in this context?
// Especially taking into account that a compiler is free to do all sorts
// of optimizations when generating code for class A
由于上述原因,类有为class A
的成员和class B
的成员使用不同的和可单独寻址的内存位置,导致这10位"溢出"到下一个可寻址内存位置——下一个字节。
当您考虑多重继承时,还会遇到更多的麻烦——在派生类中排列位的真正方法是什么?
- 将结构字段的类型展开为可变模板参数
- 将位字段导出到数组
- 为了方便起见,我应该避免公开私有字段变量吗
- 当字段可以为null时,如何使用C++接口在Avro中写入数据
- 在java中读取c++字节的位字段
- 链接器找不到在虚拟类 c++ 中访问的静态字段的符号
- 私有字段对象与私有继承?
- 声明没有默认构造函数的字段
- C++内存模型和位字段的最大序列
- 声明为无效的变量或字段'...' Ardunio 编译器上的错误
- 如何在QByteArray中放置和检索位字段而不会感到痛苦?
- C++ win32 如何使密码字段可选并启用复制和粘贴?
- 如何通过UDP接收QByteArray并将其解析为位字段结构?
- 仅匹配集合中的某些字段
- 结构字段名称与 GDB 中的 STL 数组冲突
- 如何使用位字段将数据从二进制文件复制到结构中?
- 结构体和类的不同大小(),彼此具有相同的字段类型
- 如何在不违反封装的情况下合法访问和修改私有字段矢量和映射
- 将位字段封装得更加紧密
- 理解C++中的位字段封装