Domanda

I have a problem with bitfields in derived classes.

With the g++ compiler, you can assign __attribute__((packed)) to a class and it will pack bitfields. So

class A
{
  public:
    int one:10;
    int two:10;
    int three:10;
} __attribute__ ((__packed__));

takes up only 4 bytes. So far, so good.
However, if you inherit a class, like this

class B
{
  public:
    int one:10;
    int two:10;
} __attribute__ ((__packed__));

class C : public B
{
  public:
    int three:10;
} __attribute__ ((__packed__));

I would expect class C, which has the same content as class A above, to have the same layout as well, i.e. take up 4 bytes. However, C turns out to occupy 5 bytes.

So my question is, am I doing something wrong, and if so, what? Or is this a problem with the compiler? An oversight, a real bug?

I tried googling, but haven't really come up with anything, apart from a difference between Linux and Windows (where the compiler tries to emulate MSVC), which I'm not interested in. This is just on Linux.

È stato utile?

Soluzione

I believe the problem is with B, which cannot easily be 2.5 bytes. It has to be at least 3 bytes.

Theoretically, the derived class might be allowed to reuse padding from the base class, but I have never seen that happen.

Altri suggerimenti

Imagine for a second that what you are asking for is possible. What would be possible side-effects or issues of that? Let's see on a particular example that you have. Also assume a 32-bit architecture with 1-byte memory alignment.

There are 20 consecutive bits in class A that you can address via class's members one and two. It's a very convenient addressing for you, human. But what does the compiler do to make it happen? It uses masks and bit shifts to position those bits into correct places.

So far so good, seems simple and safe enough.

Adding 10 more bits. Let's say there was some amazingly smart compiler that allows you to squeeze those extra 10 bits into an already used 32-bit word (they fit nicely, don't they?).

Here comes trouble:

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

Because of the above the class has to use different and separately-addressable memory locations for members of class A and members of class B causing those 10 bits to "spill" into next addressable memory location - next byte.

Even more trouble comes when you consider multiple inheritance - what is the one true way of arranging the bits in a derived class?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top