For example, consider the following:
Assume that int is 4-byte aligned, and long is 8-byte aligned.
struct example
{
int a;
long b;
int c;
};
the obvious way for the compiler to lay this out in memory would be: AAAAPPPPBBBBBBBBCCCCPPPP with the whole structure having an 8-byte alignment.
In this case, sizeof(example) is 24.
but another way of doing it would be the following: AAAABBBBBBBBCCCC with the whole structure having alignment such that the address of the starting byte mod 8 = 4 (not sure how to say this more succinctly)
in this case, there is no padding needed, so you save 8 bytes per instance.
My question is, are compilers allowed to do this(by the standard)? Do they actually do this? I've always seen alignment discussed simply in bytes.
Every complete object type has a property called alignment requirement, which is an integer value of type size_t representing the number of bytes between successive addresses at which objects of this type can be allocated. The valid alignment values are non-negative integral powers of two.
A 1-byte variable (typically a char in C/C++) is always aligned. A 2-byte variable (typically a short in C/C++) in order to be aligned must lie at an address divisible by 2. A 4-byte variable (typically an int in C/C++) must lie at an address divisible by 4 and so on.
An object that is "8 bytes aligned" is stored at a memory address that is a multiple of 8. Many CPUs will only load some data types from aligned locations; on other CPUs such access is just faster.
This effectively means that the address of the memory your data resides in needs to be divisible by the number of bytes required by the instruction. So in your case the alignment is 16 bytes (128 bits), which means the memory address of your data needs to be a multiple of 16.
A struct cannot have alignment requirements that are less strict than the alignment requirements of its members. If a member of the struct is 8-byte aligned, then the struct needs to be at least 8-byte aligned. If the struct is 8-byte aligned, then in your example, the second member would not be 8-byte aligned, since it is offset four bytes from the beginning of an 8-byte aligned struct, so it wouldn't meet the requirements.
The possible alternative would be to put padding at the beginning of the struct, but this is not allowed:
C++03 9.2p17
A pointer to a POD-struct object, suitably converted using a
reinterpret_cast
, points to its initial member (...) and vice-versa. [Note: There might therefore be unnamed padding within a POD-struct object, but not at its beginning, as necessary to achieve proper alignment.]
Another possible alternative would be (as your are suggesting) to have the 8-byte alignment actually mean ((address%8)==4)
(as opposed to (address%8)==0
). If that were the case though, then your 8-byte aligned long
would have the same requirement. It isn't possible to have types with both (address%8)==0
and (address%8)==4
alignment, since there would be no way to generically allocate memory that meets both alignment requirements. Since the long
would have this special alignment requirement as well, you still wouldn't be able to avoid the padding.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With