N
Noob
Hello,
I'm trying to write portable (as much as I can) alignment code.
Basically, I'm writing my own memalign function.
Function prototype:
void *aligned_malloc(size_t boundary, size_t size)
boundary shall be a power of two, and shall not be smaller
than sizeof(void *) otherwise the behavior is undefined.
Here's my first try:
#include <stdlib.h>
#include <stdint.h>
void *aligned_malloc1(size_t boundary, size_t size)
{
void *base_ptr = malloc(size + boundary);
if (base_ptr == NULL) return NULL;
size_t mask = boundary - 1;
uintptr_t res = ((uintptr_t)base_ptr + sizeof base_ptr + mask) & ~mask;
((void **)res)[-1] = base_ptr;
return (void *)res;
}
Sources of non-portability:
I used uintptr_t, which is an optional C99 type. If it's not
defined, I suppose there is no guarantee that pointers can be
represented as integers?
I suppose it is possible that sizeof(size_t) < sizeof(uintptr_t)
but I don't think that would cause a problem?
It is allowed to cast from (void *) to uintptr_t (and back) but
I don't think it is allowed to manipulate a uintptr_t, then cast
it to (void *) and expect a valid pointer. I think I can work
around this by computing an offset?
Here's my second try:
#include <stdlib.h>
#include <stdint.h>
void *aligned_malloc2(size_t boundary, size_t size)
{
void *base_ptr = malloc(size + boundary);
if (base_ptr == NULL) return NULL;
size_t mask = boundary - 1;
uintptr_t base = (uintptr_t)base_ptr;
uintptr_t addr = (base + sizeof base_ptr + mask) & ~mask;
void *res = (unsigned char *)base_ptr + (addr - base);
((void **)res)[-1] = base_ptr;
return res;
}
My compiler generates slightly different code for the two functions.
(gcc -Wall -Wextra -std=c99 -pedantic -O3 -fomit-frame-pointer)
Is aligned_malloc2 truly more portable than aligned_malloc1?
Do you see ways to improve aligned_malloc2?
Regards.
I'm trying to write portable (as much as I can) alignment code.
Basically, I'm writing my own memalign function.
Function prototype:
void *aligned_malloc(size_t boundary, size_t size)
boundary shall be a power of two, and shall not be smaller
than sizeof(void *) otherwise the behavior is undefined.
Here's my first try:
#include <stdlib.h>
#include <stdint.h>
void *aligned_malloc1(size_t boundary, size_t size)
{
void *base_ptr = malloc(size + boundary);
if (base_ptr == NULL) return NULL;
size_t mask = boundary - 1;
uintptr_t res = ((uintptr_t)base_ptr + sizeof base_ptr + mask) & ~mask;
((void **)res)[-1] = base_ptr;
return (void *)res;
}
Sources of non-portability:
I used uintptr_t, which is an optional C99 type. If it's not
defined, I suppose there is no guarantee that pointers can be
represented as integers?
I suppose it is possible that sizeof(size_t) < sizeof(uintptr_t)
but I don't think that would cause a problem?
It is allowed to cast from (void *) to uintptr_t (and back) but
I don't think it is allowed to manipulate a uintptr_t, then cast
it to (void *) and expect a valid pointer. I think I can work
around this by computing an offset?
Here's my second try:
#include <stdlib.h>
#include <stdint.h>
void *aligned_malloc2(size_t boundary, size_t size)
{
void *base_ptr = malloc(size + boundary);
if (base_ptr == NULL) return NULL;
size_t mask = boundary - 1;
uintptr_t base = (uintptr_t)base_ptr;
uintptr_t addr = (base + sizeof base_ptr + mask) & ~mask;
void *res = (unsigned char *)base_ptr + (addr - base);
((void **)res)[-1] = base_ptr;
return res;
}
My compiler generates slightly different code for the two functions.
(gcc -Wall -Wextra -std=c99 -pedantic -O3 -fomit-frame-pointer)
Is aligned_malloc2 truly more portable than aligned_malloc1?
Do you see ways to improve aligned_malloc2?
Regards.