0

i have one question, I know the padding is for an efficient access of variables in memory, but imagine, if we only can access memory in chunks of 8 bytes (if is a 64 bit computer), and we have 3 variables, 1 char 1 int and 1 char, not in a struct, and imagine that the stack pointer points to the beginning of one of those 8 bytes chucks, couldn't the compiler not add the padding?

I already understood the propose of padding, but it seems at first look unnecessary waste of memory, in a lot of cases.

  • If they are simple local variables, good chance they are mapped to CPU registers rather than memory. – Erik Eidt Jun 18 '23 at 16:42
  • 4
    Your premise is incorrect; all current mainstream 64-bit CPUs have byte-addressable memory and [can load/store naturally-aligned 1, 2, 4, or 8-byte chunks](https://stackoverflow.com/questions/46721075/can-modern-x86-hardware-not-store-a-single-byte-to-memory). (Many can also do unaligned loads/stores, which compilers will sometimes use to initialize two or more struct members at once.) Local vars not in a struct can be laid out in any order, so the compiler is free to order them as int, char, char with two contiguous bytes left in a 64-bit chunk, or with the `int` as the high half of a 64bit – Peter Cordes Jun 18 '23 at 17:15
  • its about performance, memory is cheap relative to performance. if you are willing to accept the performance hit compilers often let you pack the struct. – old_timer Jun 19 '23 at 06:30

2 Answers2

0

In case you allocate individual variables, the compiler is free to allocate them as it pleases, at any address or in any order. Naturally it will do this with alignment in mind, but also perhaps with optimizer settings: optimize for speed vs size. Depending on CPU, it may or may not support misaligned access, or it might not have alignment requirements at all.

When programming hardware-related programs, there is often a need to allocate variables in a certain order. The code might be modelling a data communications protocol, a hardware register map, an image memory layout etc etc. The only mechanism C provides to guarantee an order of least significant -> most significant address allocation is struct. Therefore, C explicitly forbids the compiler to change allocation order of the members of a struct.

(In theory, C is also supposed to support bit-field members of a struct, though in practice the feature is so under-specified by the standard that it can't be used reliably.)

Therefore padding optimization of a struct by the compiler isn't possible - it has to allocate the members in the order specified by the programmer, even if that means adding lots of dead padding bytes to suit alignment. This problem only exists if the struct uses members smaller than the alignment requirement(s) supported by the CPU, however.

One trick to memory-optimize when struct order of allocation isn't needed, is that instead of having a struct with n members, create n different arrays, each array having the type of one of the members. The array index then becomes the association between which array members that belong to the same group, rather than the mystruct.member syntax.

There are also non-standard ways to disable padding, but they aren't portable and usually a last resort - since the padding was added for a reason. With or without padding enabled, if you need truly portable structs, you may have to write manual serialization/deserialization routines that memcpy member by member.

Lundin
  • 195,001
  • 40
  • 254
  • 396
-1

Any compiler will produce the smallest possible amount of padding. A C++ compiler can sometimes rearrange the order of struct members to reduce padding.

You'd need to check first what the processor can actually do. Say your processor can read bytes at any address, 16 bit words at an even address, 32 bits at a multiple of four, 64 bits at a multiple of eight. If your struct is byte / eight bytes / byte, then your offsets are 0, 8, 16. Change it to byte / byte / eight bytes, then your offsets are 0, 1, 8.

Now array elements must be correctly aligned, and there are no gaps between array elements. So in the first case, the struct must be a multiple of eight bytes, so it is 24 bytes. In the second case, it also must be a multiple of eight bytes, but only 16 bytes are needed. A C compiler can't do anything about that.

On the stack, the compiler is free to reorder variables, so it can (with this processor) put two bytes into neighbouring bytes without padding, for example. The padding itself cannot be avoided because you can't have non-existing memory. If one variable is at location 100 and one at 108, there must be something in between.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • 5
    "_A C++ compiler can sometimes rearrange the order of struct members to reduce padding._": Only rearranging by interleaving the groups of different access specifier was ever allowed, but inside such a group the order had to match the declared one, and since C++20 even that isn't permitted anymore. (It was a weird exception anyway.) I am not sure that any ABI ever permitted it. – user17732522 Jun 18 '23 at 16:26
  • 1
    This question was never tagged "C++". – Lundin Jun 19 '23 at 08:29