Reputation:
I'm having trouble understand what the purpose of the alignas
and alignof
keywords are, and I'm not quite sure I fully understand what alignment is.
As I understand it, a memory address is aligned to n bytes if it is divisible by n, that is, it can be got to by counting 'n' bytes at a time (from 0? or some default value?). Also, the alignas
keyword, when prefixing a variable declaration, specifies how the address at which the variable is stored is to be aligned, and the alignof
returns how a variable's address is aligned.
However, I am not confident that this is a correct understanding of alignment or the alignof
/alignas
keywords - please correct me on any of the points I got wrong. I also don't see what use these keywords serve, so I would appreciate it if anyone could point out what their purpose is.
Upvotes: 8
Views: 1853
Reputation: 290
As I understand it, a memory address is aligned to n bytes if it is divisible by n, that is, it can be got to by counting 'n' bytes at a time (from 0? or some default value?).
Yes, it is normally congruent to 0, because it is a hardware alignment, similar to an alignment on cylinders of (old) hard disks (see Cylinder-head-sector). Well, I’m not sure I’m right with this things of cylinders; I’m not keen on hardware.
I’ve never used alignas
, but clearly it can be useful for optimization in interaction with some hardware. For instance, although it’s not for RAM, in the man page of gcc
you can see the -falign-*
optimization options, with an explanation of their purpose: align some code in the output so that the CPU can fetch more instructions at once.
With common scalar types, you will normally have sizeof(your_type)
being equal to alignof(your_type)
, which is for optimization. But for a compound type (array or struct), the value will be different and usually equal to the maximum alignment required by one of the members.
Without regard for more hardware than the RAM, this can be useful for some generic data management functions. Of course, allocation functions such as malloc()
always give you an address which is convenient for any type, that is, aligned for max_align_t
which usually has an alignof
of 16 (as required by long double
). But this year, I have worked on a project which uses only one malloc()
to allocate a matrix and pointers to each row of the matrix, in the same block, for a variable of type int * *
for example. So the block shall contain first the space for the int *
pointers and then the space for the int
values. Because (on common systems) alignof(int *) % alignof(int) == 0
, there is no problem in this case. But on a 32-bit architecture, it would fail with double
or int64_t
for example, because the pointers are 4-bytes long and the values require an alignment of 8. So alignof
must be used to determine a correct start for the values (and the padding must be added to the allocated size, of course). In my case, this was not done yet, and it was not a problem because the program was only tested on 64-bit architectures and did not use long double
or alike. But I’ve done the fix, so that the program can surely work on 32-bit machines.
If I understand correctly, alignof(type)
is equivalent to offsetof(struct char_and_type, item)
if you have:
struct char_and_type {
char c;
type item;
};
Upvotes: 0
Reputation: 146968
Some special types must be aligned at more bytes than usual- for example, matrices must be aligned at 16bytes on x86 for the most efficient copying to the GPU. SSE vector types can behave this way too. As such, if you want to make a container type, then you must know the alignment requirements of the type you're trying to contain or allocate.
Upvotes: 8