Why aligning of long long union member is bigger t

2019-02-16 21:50发布

问题:

From this question one could start to believe that alignment of a union is not less than the largest alignment of it's individual members. But I have a problem with the long long type in gcc/g++. The full example can be found here, but here are the relevant parts for my question:

union ull {
  long long m;
};

struct sll {
  long long m;
};


int main() {
#define pr(v) cout << #v ": " << (v) << endl
   pr(sizeof(long long));
   pr(__alignof__(long long));
   pr(sizeof(ull));
   pr(__alignof__(ull));
   pr(sizeof(sll));
   pr(__alignof__(sll));
};

This results in the following output:

sizeof(long long): 8
__alignof__(long long): 8
sizeof(ull): 8
__alignof__(ull): 4
sizeof(sll): 8
__alignof__(sll): 4

Why is the alignment of a union member bigger than that of the containing union?

[UPDATE]

According to Keith's answer alignof is wrong here. But I test the following and it seems that alignof tells us the true. See:

union ull {
  long long m;
};
long long a;
char b;
long long c;
char d;
ull e;
int main() {
#define pr(v) cout << #v ": " << (v) << endl
   pr(size_t((void*)&b));
   pr(size_t((void*)&c));
   pr(size_t((void*)&d));
   pr(size_t((void*)&e));
   pr(size_t((void*)&c) - size_t((void*)&b));
   pr(size_t((void*)&e) - size_t((void*)&d));
};

The output:

size_t((void*)&b): 134523840
size_t((void*)&c): 134523848
size_t((void*)&d): 134523856
size_t((void*)&e): 134523860
size_t((void*)&c) - size_t((void*)&b): 8
size_t((void*)&e) - size_t((void*)&d): 4

So, the alignment of long long is 8 and alignment of union containing long long is 4 in global data. For local scope I cannot test this since it seems that compiler is free to rearrange local data - so this trick does not work. Can you comment on this?

[/UPDATE]

回答1:

__alignof__ (which is a gcc extension) doesn't necessarily report the required alignment for a type.

x86 processors, for example don't really require more than 1-byte alignment for any type. Access to a 4-byte or 8-byte object will likely be more efficient if the object is word-aligned, but byte alignment is sufficient.

Quoting the gcc documentation:

Some machines never actually require alignment; they allow reference to any data type even at an odd address. For these machines, __alignof__ reports the smallest alignment that GCC will give the data type, usually as mandated by the target ABI.

But that still doesn't really answer the question. Even with that loose definition, I can't think of any good reason for __alignof__ to indicate a stricter alignment for long long than for a struct or union containing a long long.

A more portable method of determining the alignment of a type is this:

#define ALIGNOF(type) ((int)(offsetof(struct {char c; type t;}, t)))

This yields the offset of a member of type t in a struct consisting of a char and a t. Using this macro, this program:

#include <iostream>
#include <cstddef>

union ull {
  long long m;
};

struct sll {
  long long m;
};

#define ALIGNOF(type) ((int)(offsetof(struct {char c; type t;}, t)))

int main() {
#define pr(v) std::cout << #v ": " << (v) << std::endl
   pr(sizeof(long long));
   pr(__alignof__(long long));
   pr(ALIGNOF(long long));
   pr(sizeof(ull));
   pr(__alignof__(ull));
   pr(ALIGNOF(ull));
   pr(sizeof(sll));
   pr(__alignof__(sll));
   pr(ALIGNOF(sll));
};

produces this output on my system (gcc-4.7, Ubuntu 12.04, x86):

sizeof(long long): 8
__alignof__(long long): 8
ALIGNOF(long long): 4
sizeof(ull): 8
__alignof__(ull): 4
ALIGNOF(ull): 4
sizeof(sll): 8
__alignof__(sll): 4
ALIGNOF(sll): 4

The results indicated by my ALIGNOF() macro are consistent: long long has 4-byte alignment, and a struct or union containing a long long has 4-byte alignment.

I suspect this is a bug, or at least an inconsistency, in gcc's implementation of __alignof__. But the vagueness of the definition makes it hard to be certain that it's really a bug. It doesn't seem to have been reported.

Update :

I may be jumping the gun, but I've just submitted a bug report.

This earlier bug report, closed as "INVALID", is similar, but it doesn't refer to the alignment of the structure itself.

Update 2 :

My bug report has been closed as a duplicate of the earlier one. I'll be asking for clarification.