I have to implement an optimized version of malloc/realloc/free (tailored for my particular application). At the moment the code runs on a particular platform, but I would l
The main problem is that you only provide the total size of the memory block to malloc()
and friends, without any information about the object granularity. If you view an allocation as an array of objects, then you have a size that is the sizeof of the basic object, and a number n that is the number of objects in the array, e.g.:
p = malloc(sizeof(*p) * n);
If you have only the total size, then you don't know if s=4 and n=10, or if s=2 and n=20, or s=1 and n=40, because all multiply to the total size of 40 bytes.
So the basic question is, do you want a direct substitute for the original functions, e.g. when you have thrown native calls all over your code base, or do you have a centralized and DRY modularity with wrapper functions. There you could use functions that provide s and n.
void *my_malloc (size_t s, size_t n)
Most of the time it should be a safe bet when the returned absolute memory address is a multiple of s to guarantee correct alignment.
Alternatively, when porting your implementation, you simply look at the alignment that the native malloc()
uses for the target platform (e.g. multiples of 16), and use this for your own implementation.
If you have a look at #pragma pack, this may help you as it allows you to define structure packing and is implemented on most compilers.
aligned memory differs from compiler to compiler unfortunately (this is one issue), on MSVC, you have aligned_malloc
, you also have POSIX memalign for Linux, and then there is also _mm_alloc
which works under ICC, MSVC and GCC, IIRC, which should be the most portable.
The second issue is memory wastage from aligning it, it wouldn't be major, but on embedded systems, its something to take note of.
if you are stack allocating things that require alignment (like SIMD types), you also want to look into __attribute__((__aligned__(x)))
and __declspec(align(x))
.
in terms of portability of pointer arithmetic, you can use the types from stdint.h
/pstdint.h
to do it, but the standards may say something about UB when casting between uintptr_t
and a pointer (unfortunately standards aren't my strong point :().
Alignment features are only handled in the new C standard, C11. It has keywords _Alignof
, _Alignas
and a function aligned_alloc
. Theses features are not very difficult to emulate with most modern compilers (as indicated in other answers), so I'd suggest you write yourself small macros or wrappers that you'd use depending on __STDC_VERSION__
.
C says malloc
returns a pointer to memory aligned for any purpose. There is no portable way in C to achieve that with C features. This has the consequence that malloc
is a function that if written in C cannot be written in a portable way.
(C99, 7.20.3p1) "The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated)."
The classic way to ensure that you maintain alignment suitable for all the basic types is to define a union:
union alloc_align {
void *dummy1;
long long dummy2;
long double dummy3;
};
...then ensure that the addresses you hand out are always offset by a multiple of sizeof (union alloc_align)
from the aligned addresses you recieve from the system memory allocator.
I believe a method similar to this is described in K&R.