3

我对派生类中的位域有疑问。

使用 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 上。

4

2 回答 2

0

我相信问题出在 B 上,它不容易是 2.5 字节。它必须至少为 3 个字节。

从理论上讲,派生类可能被允许重用基类的填充,但我从未见过这种情况发生。

于 2012-07-25T09:45:39.460 回答
0

想象一下,你所要求的可能的。有什么可能的副作用或问题?让我们看看你有一个特定的例子。还假设具有 1 字节内存对齐的 32 位架构。

有 20 个连续位class A,您可以通过类的成员onetwo. 这对你来说是一个非常方便的寻址方式,人类。但是编译器做了什么来实现它呢?它使用掩码和位移位将这些位定位到正确的位置。

到目前为止一切顺利,似乎足够简单和安全。

再增加 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

由于上述原因,该类必须为10 位“溢出”到下一个可寻址内存位置 - 下一个字节的成员和成员使用不同且可单独寻址的内存位置。class Aclass B

当您考虑多重继承时,更麻烦的是——在派生类中排列位的一种真正方法是什么?

于 2012-07-25T09:58:02.053 回答