1

It's a bit hard to formulate what I want to know in a single question, so I'll try to break it down.

For example purposes, let's say we have the following struct:

struct X {
  uint8_t a;
  uint16_t b;
  uint32_t c;
};
  1. Is it true that the compiler is guaranteed to never rearrange the order of X's members, only add padding where necessary? In other words, is it always true that offsetof(X, a) < offsetof(X, c)?

  2. Is it true that the compiler will pick the largest alignment among X's members and use it to align objects of type X (i.e. addresses of X instances will be divisible by the largest alignment among X's members)?

  3. Since malloc does not know anything about the type of objects that we're going to store when we allocate a buffer, how does it choose an alignment for the returned address? Does it simply return an adress that is divisible by the largest alignment possible (in which case, no matter what structure we put in the buffer, the memory accesses will always be aligned)?

3 Answers3

3
  1. Yes
  2. No, the compiler will use its knowledge of the target host hardware to select the best alignment.
  3. See question 2.
Carey Gregory
  • 6,836
  • 2
  • 26
  • 47
2

Since malloc does not know anything about the type of objects that we're going to store when we allocate a buffer, how does it choose an alignment for the returned address?

malloc(3) returns "memory that is suitably aligned for any kind of variable."

Does it simply return an adress that is divisible by the largest alignment possible (in which case, no matter what structure we put in the buffer, the memory accesses will always be aligned)?

Yes, but watch your compliance with the strict aliasing rule.

Community
  • 1
  • 1
Kevin
  • 28,963
  • 9
  • 62
  • 81
  • Kevin, I am sorry to bother you but I am desperate :) `malloc()` returns memory suitably aligned for any type. Every child in kindergarten knows that. How about return of `mmap()` ? Surely, the answer must be "suitably aligned for any type" because, after all, it is a page boundary. So what? - where is it documented in C or Linux/POSIX standard?? – Mark Galeck Dec 01 '22 at 07:31
1

The compiler will do whatever is most beneficial on that computer in the largest number of circumstances. On most platforms loading bus wide values on bus width offsets is fastest.

That means that generally on 32-bit computers compilers will chose to align 32-bit numbers on 4 byte offsets. On 64-bit computers 64-bit values are aligned on 8 byte offsets.

On most computers smaller values like 8-bit and 16-bit values are slower to load. Probably all 4 or 8 bytes around it are loaded and the byte or two bytes you need are masked off.

When you have special circumstances you can override the compiler by specifying the alignment and the padding. You might do this when you know fast loading is not important, but you really want to pack the data tightly. Or when you are playing very subtle tricks with casting and unions.

Memory allocation routines on almost any modern computer will always return memory that is aligned on at least the bus width of the platform ( e.g. 4 or 8 bytes ) - or even more - like 16 byte alignment.

When you call "malloc" you are responsible for knowing the size of the structures you need. Luckily the compiler will tell you the size of any structure with "sizeof". That means that if you pack a structure to save memory, sizeof will return a smaller value than an unpacked structure. So you really will save memory - if you are allocating small structures in large arrays of them.

If you allocate small packed structures one at a time - then yes - if you pack them or not it won't make any difference. That is because when you allocate some odd small piece of memory - the allocator will actually use significantly more memory than that. It will allocate an convenient sized block of memory for you, and then an additional block of memory for itself to keep track of you allocation.

Which is why if you care about memory use and want to pack your structures - you definitely don't want to allocate them one at time.

Rafael Baptista
  • 11,181
  • 5
  • 39
  • 59