We read a lot about alignment and how important it is, for example for placement new
usage, but I was wondering - how does it exactly alter the layout of the memory?
Obviously, if we do
char buffer[10];
std::cout << sizeof buffer;
and
alignas(int) char buffer[10];
std::cout << sizeof buffer;
we get the same result, which is 10
.
But the behaviour cannot be exactly the same, can it? How come it is distinguishable? I tried to seek the answer and ran to godbolt, testing the following code:
#include <memory>
int main() {
alignas(int) char buffer[10];
new (buffer) int;
}
which, under GCC 8.2 and no optimisations, results in following assembly:
operator new(unsigned long, void*):
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov QWORD PTR [rbp-16], rsi
mov rax, QWORD PTR [rbp-16]
pop rbp
ret
main:
push rbp
mov rbp, rsp
sub rsp, 16
lea rax, [rbp-12]
mov rsi, rax
mov edi, 4
call operator new(unsigned long, void*)
mov eax, 0
leave
ret
Let's change the code slightly by removing the alignas(int)
part. Now, the generated assembly is slightly different:
operator new(unsigned long, void*):
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov QWORD PTR [rbp-16], rsi
mov rax, QWORD PTR [rbp-16]
pop rbp
ret
main:
push rbp
mov rbp, rsp
sub rsp, 16
lea rax, [rbp-10]
mov rsi, rax
mov edi, 4
call operator new(unsigned long, void*)
mov eax, 0
leave
ret
Notably, it differs only by lea
instruction, where the second parameter is [rbp-10]
instead of [rbp-12]
, as we had in the alignas(int)
version.
Please do note that I generally do not understand assembly. I cannot write assembly but I can somewhat read it. To my understanding, the difference simply alters the offset of a memory addres, which will hold our placement-new
ed int
.
But what does it achieve? Why do we need that? Suppose we have a 'generic' representation of the buffer
array as follows:
[ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ]
Now, I would assume, that after placement-new
ing the int
(with or without the alignment), we would end up with something like this:
[x] [x] [x] [x] [ ] [ ] [ ] [ ] [ ] [ ]
where x
represents a single byte of an int
(we assume that sizeof(int) == 4
).
But I must be missing something. There is more to that and I do not know what. What exactly do we achieve by aligning the buffer
to int
suited alignment? What happens if we don't align it so?