user44990
user44990

Reputation: 41

Malloc and unaligned memory

malloc() documentation says that the returned pointer is suitably aligned for any kind of variable. On my system, a long double has size 12, however some pointers returned by malloc() are aligned on 8 byte boundary and not 12. (ptr % 12 gives 4). Can anybody point out what am I missing here? Thanks in advance.

Upvotes: 4

Views: 2087

Answers (5)

Christoph
Christoph

Reputation: 169693

You're missing that while a type's size must be a multiple of its alignment (which is restricted by the actual hardware), they need not be equal.

In case of long double, this translates to

_Alignof (long double) == 4
sizeof (long double) == 12

with gcc/x86 and

_Alignof (long double) == 16
sizeof (long double) == 16

with gcc/x64, where in both cases long double has 80-bit extended precision.

If we were not restricted by alignment, most naturally we'd end up with

sizeof (long double) == 10

In the presence of alignment, we'd either have to go with an alignment of 2 (which we don't for efficiency reasons), or introduce padding to arrays so elements align correctly. This violates C language semantics were an array's size is the product of its element size and count.

Upvotes: 0

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215427

On any sane cpu architecture, the largest possible alignment requirement for an object of size 12 is 4. The alignment requirement must be a power of 2 that divides the size of the type evenly. Indeed this gives very poor alignment (objects spanning cache lines or even pages!), which is why the x86_64 ABI changed the size of long double to 16: so that it would be possible to align it not to cross any boundaries.

Upvotes: 3

user395760
user395760

Reputation:

Evidently, long double need not be aligned to 12 bytes. On systems such as yours, the largest alignment for a primitive C type is 8 bytes for double. Don't confuse alignment and size - while many smaller (especially primitive) types must be naturally aligned - that is, aligned to their own size - this is prohibitive for larger data types (think fragmentation) and doesn't make anything easier for the hardware.

Upvotes: 5

Bryan Olivier
Bryan Olivier

Reputation: 5307

malloc will return memory properly aligned for any type, because typically the pointer it returns is converted to a pointer of an arbitrary type and such conversion is typically (read: infinitely close to 100% of the time) a no-op. For any architecture and compiler the maximum alignment of any type is however a constant and typically it is the maximum of the alignment of all primitive types. The size of an object should however be a multiple of its alignment. Sometimes this requirement must be met by adding padding to the value inside the object.

If your compiler is modern enough it will support _Alignof, similar to sizeof, so you can check the actual alignment with a small program. I think on your architecture the maximum alignment is 4. If malloc always returns addresses aligned by 8, then it still complies. It is not unusual for malloc to meet an alignment that is a multiple of the maximum alignment of the types.

Upvotes: 0

ouah
ouah

Reputation: 145899

On gcc for Linux and x86 you have:

sizeof (long double) == 12

and

on gcc for Linux and x64 you have:

sizeof (long double) == 16

The ABI alignment requirements for x64 long double is 16-bytes. For x86, no type requires more than 8-bytes of alignment.

To respect that glibc malloc returns memory object aligned with 8-bytes on 32-bit system and aligned on 16-bytes for 64-bit systems.

From glibc doc:

The block that malloc gives you is guaranteed to be aligned so that it can hold any type of data. On GNU systems, the address is always a multiple of eight on most systems, and a multiple of 16 on 64-bit systems.

Upvotes: 4

Related Questions