my latest test is failing, but i think i've found a solution to pass it. it involves using alignof(max_align_t) (or even alignof(long double)), but i'm not entirely sure if my understanding of allocation alignment is correct..
my idea is that if the actual size of my type is not divisible by the address position, i need to add some padding until the condition is satisfied. this process helps the compiler access memory more efficiently by creating a predictable pattern!
if i'm right, so why the last test is not passing? otherwise, clarification would be appreciated!
void *malloc(size_t sz, const char *file, int line) {
(void)file, (void)line; // avoid uninitialized variable warnings
if (default_buffer.pos + sz > default_buffer.size) {
// Not enough space left in default buffer for allocation
gstats.nfail++;
gstats.fail_size += sz;
return nullptr;
}
// Here i'm checking for correct allocation alignement
if (default_buffer.pos % sz != 0) {
default_buffer.pos += default_buffer.pos % sz;
}
// Otherwise there is enough space; claim the next `sz` bytes
void *ptr = &default_buffer.buffer[default_buffer.pos];
default_buffer.pos += sz;
gstats.ntotal++;
gstats.total_size += sz;
return ptr;
}
test.c
int main() {
double* ptr = (double*) malloc(sizeof(double));
assert((uintptr_t) ptr % alignof(double) == 0);
assert((uintptr_t) ptr % alignof(unsigned long long) == 0);
assert((uintptr_t) ptr % alignof(std::max_align_t) == 0);
char* ptr2 = (char*) malloc(1);
assert((uintptr_t) ptr2 % alignof(double) == 0);
assert((uintptr_t) ptr2 % alignof(unsigned long long) == 0);
assert((uintptr_t) ptr2 % alignof(std::max_align_t) == 0);
free(ptr);
free(ptr2);
}
I've already solved the problem, and I want to understand why an alternative to my solution is not working on a specific test. So basically, I'm seeking to ensure my understanding is correct!

As I mentioned in the comments, your alignment calculation is not correct. Imagine you want an alignment of 4, and the residual of modulo is 3. You would not add another 3 -- you would add 4 minus 3.
Instead of using modulo, the typical way to align a value is to add one less than the alignment (so that everything except zero is guaranteed to result in an address at the next alignment boundary), and then mask off all the bits lower than the alignment:
Note that
alignmust be an unsigned power of 2.Since you're trying to align a position in a buffer here, you must also be careful that this actually results in the same alignment in memory.
Regarding automatic alignment, the user Eric Postpischil also commented:
So, putting all this together here's a simple way you can align to an arbitrary address:
Note the dirty trick for trimming down to
sizeof(max_align_t). This may or may not be better than simply introducing a branch. I'm not much of a bit-basher!See it in action:
Example output: