8

I am getting unexpected results when running the following code for 32-bit x86 linux (compiler flags: g++ -std=c++14 -m32). I tried gcc and clang.

#include <iostream>
using namespace std;

struct S1
{
  uint64_t a;
  uint32_t b;
};

struct S2
{
  alignas(uint64_t) char a[8];
  uint32_t b;
};

int main()
{
  cout << "sizeof(S1)=" << sizeof(S1) << endl;
  cout << "sizeof(S2)=" << sizeof(S2) << endl;
}

The output is:

sizeof(S1)=12
sizeof(S2)=16

What is happening here? Why are S1 and S2 of different size? As I understand it, 64 bit integer values are aligned to 32 bit on 32-bit x86 machines. This does explain why the size of S1 is 12 bytes. But why does this not apply to S2?

user3809741
  • 121
  • 2
  • Possibly cache row alignment for character array `a` includes one extra 4-byte block for the array for make S2 16 bytes? Possibly related: http://stackoverflow.com/questions/17091382/memory-alignment-how-to-use-alignof-alignas – dfrib Jan 06 '16 at 13:39
  • 2
    This is not an answer but progress. `alignas(uint64_t)` is defined as the same as `alignas(alignof(uint64_t))`. If you add `cout << alignof(uint64_t) << endl ;` to the example you'll get an output of 8 (gcc at least). So the question should be 'why does gcc think alignof(uint64_t) is 8 when it's 4 on the platform in question. NB: It has to be 4 because sizeof(S1) is 12. – Persixty Jan 06 '16 at 13:51
  • To see if the difference in size may be related to the fact that you are using a `char[8]`, Could you please replace, in `S2`: `alignas(uint64_t) char a[8];` with **another 64 bits type**, like for example a `double`? – arainone Jan 06 '16 at 14:09
  • @arainone I think that will only confuse matters. `alignof(double)` is typically 8 anyway. So `sizeof(S2)` would be 16 without the alignas(uint64_t). As I mentioned gcc says alignof(uint64_t) is 8. That appears to be the root of the problem. – Persixty Jan 06 '16 at 14:17
  • 2
    This seems to be related to [this question](http://stackoverflow.com/questions/11825081/why-aligning-of-long-long-union-member-is-bigger-than-the-containing-union-struc). And possibly to [this thread of gcc mailing list](https://gcc.gnu.org/ml/gcc/2009-06/msg00333.html) – arainone Jan 06 '16 at 14:38

1 Answers1

4

The alignof keyword measures the alignment of a type as a complete object; i.e. when it is allocated as an individual object or array element. This is not necessarily the same as the alignment requirements of that type as a subobject; Are members of a POD-struct or standard layout type guaranteed to be aligned according to their alignment requirements?

The alignment of a 64-bit integer within a struct is mandated by the x386 ABI at 4 bytes; gcc is not at liberty to change this, as it would break binary compatibility with other object files and programs. However, it can align complete-object 64-bit integers to 8 bytes, as doing so does not affect the ABI, and makes for more efficient access to memory.

Community
  • 1
  • 1
ecatmur
  • 137,771
  • 23
  • 263
  • 343