Why aligning of long long union member is bigger than the containing union/struct? Is this correct?
Asked Answered
R

1

8

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]

Ridenhour answered 6/8, 2012 at 8:48 Comment(2)
I see the same thing on Red Hat, gcc 4.7.0 with -m32, but not with -m64 (all 8s).Psychosexual
gcc.gnu.org/bugzilla/show_bug.cgi?id=52023 a link to the corresponding gcc bug for _Alignof (C11).Geum
D
7

__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.

Diandiana answered 6/8, 2012 at 9:10 Comment(4)
Thanks much for this ALIGNOF() hint.Ridenhour
However this macro doesn't work for NonPOD types since offsetof does not work with NonPOD (see #1130394). Do you by chance know solution for NonPOD types?Ridenhour
can you comment on my update. It seems that __alignof__(long long)==8 is correct. And what is tested with your ALIGNOFis just aligning of long long in struct which is the same case as my struct sll { long long m; }. Maybe this help for your bug report.Ridenhour
@PiotrNycz: It's tricky; an object that's 8-byte aligned is also 4-byte aligned, so showing that a long long object has an 8-byte aligned address doesn't demonstrate that its alignment is 8. But further experiment shows that gcc does seem to be aligning long long objects at 8-byte boundaries, and struct { long long x; } objects at 4-byte boundaries.Diandiana

© 2022 - 2024 — McMap. All rights reserved.