Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it in C++ standard to align such structures

Tags:

c++

x86

Take this example

class A
{
public:
  int a; 
  char b;
  int c;
};

Every compiler (for x86, 32 or 64 bit) I see allocates 12 bytes for class A, instead of 9. So they are aligning b to the integer boundary or bus boundary you can say. My question is if this is in C++ standard to do so and if there are any compilers who does not do like that.

like image 609
pythonic Avatar asked Nov 08 '12 14:11

pythonic


1 Answers

The C++ standard specifies that:

  • objects have an alignment requirement of which their size is a multiple (so if int is 4 bytes wide, then it requires an alignment of 1, 2 or 4 bytes, depending on the implementation).
  • member objects (if they are not separated by access specifiers such as public) are all allocated in the order they're declared
  • and they are allocated respecting their alignment requirements.

So no, the standard doesn't say exactly that the class should have a size of 12 bytes.

But it does say that b should be allocated after a, and that c should be allocated after b.

On a platform where int is 4 bytes wide, and requires 4-byte alignment, this leaves 12 bytes as the smallest valid size:

  • a takes the first 4 bytes
  • b takes one byte
  • c needs 4 bytes, but must be allocated on a 4-byte boundary. b ended one byte past such a boundary, so the next valid position to place c at is found by inserting 3 bytes of padding.

So the total size of the class ends up being the size of the members (4 + 1 + 4 = 9) plus three bytes of padding, for a total of 12.

There is another rule which has no effect here, but which would matter if you had defined the members in the order a, c, b instead.

The containing class (A) inherits the alignment requirement from the strictest-aligned member object. That is, because it contains an int, it has the same alignment requirement as an int does. And because the object's total size must be a multiple of its alignment requirement, a class containing the members in the order a, b, c would still require 12 bytes of storage. It'd just shift the 3 bytes of padding to the end of the class, instead of between b and c.

However, in some other cases, reordering members in descending order of size can sometimes reduce the size of a class.

Suppose we'd had a class like this instead:

class B {
  char a;
  double b;
  int c;
};

This would have required 24 bytes of storage (1 bytes for a, 8 byte for b, and 4 bytes for c, but then to ensure b ends up on an 8-byte boundary, we'd need 7 bytes of padding between a and b, and to ensure that the whole class ends up with a size that is a multiple of 8, we need another 4 bytes after c.

But reordering the members according to size, like this:

class B {
  double b;
  int c;
  char a;
};

results in a class requiring only 16 bytes:

the same 1 + 4 + 8 bytes for the member objects themselves, but now c is already aligned on a 4-byte boundary (because it comes after b which ends on an 8-byte boundary), and a never needs any alignment, so the only alignment we need is to ensure that B has a size that is a multiple of 8. The members take 13 bytes, so we can add 3 bytes of padding, and the class ends up at 16 bytes, 33% smaller than the first version.

like image 198
jalf Avatar answered Sep 20 '22 14:09

jalf