Fwiw, this is some old C code I just cobbled up to work with C++; used
it as a region allocator in the past:
https://groups.google.com/forum/#!original/comp.lang.c/7oaJFWKVCTw/sSWYU9BUS_QJ
Well, "work" with C++ or even C is very loose here. Its a total hack to
force align objects on large boundaries. This is very useful wrt
designing different exotic algorithms. However, I think its forever
doomed wrt UB. I am not sure how to ever make it work in a 100% portable
way. When I say a large boundary, I mean say, 2048 bytes are much
bigger. Well, here is some code, can you even get it to run without
tripping an assert or getting a throw?
______________________
#include <iostream>
#include <new>
#include <cassert>
#include <cstdlib>
#include <cstddef>
#include <cstdint>
// Doctor Hackinstein!
#define CT_RALLOC_ALIGN_UP(mp_ptr, mp_align) \
((unsigned char*)( \
(((std::uintptr_t)(mp_ptr)) + ((mp_align) - 1)) \
& ~(((mp_align) - 1)) \
))
#define CT_RALLOC_ALIGN_ASSERT(mp_ptr, mp_align) \
(((unsigned char*)(mp_ptr)) == CT_RALLOC_ALIGN_UP(mp_ptr, mp_align))
// Hackish indeed!
template<std::size_t T_size>
struct ct_local_mem
{
unsigned char m_bytes[T_size];
template<typename T>
unsigned char* align_mem()
{
return align_mem<T>(alignof(T));
}
template<typename T>
unsigned char* align_mem(unsigned long align)
{
if (!align) align = alignof(T);
unsigned char* base = m_bytes;
unsigned char* aligned = CT_RALLOC_ALIGN_UP(base, align);
assert(CT_RALLOC_ALIGN_ASSERT(aligned, align));
std::size_t size = aligned - m_bytes;
if (size + sizeof(T) + align > T_size)
{
throw;
}
return aligned;
}
};
// A test program...
struct foo
{
int m_a;
int m_b;
foo(int a, int b) : m_a(a), m_b(b)
{
std::cout << this << "->foo::foo.m_a = " << m_a << "\n";
std::cout << this << "->foo::foo.m_b = " << m_b << "\n";
}
~foo()
{
std::cout << this << "->foo::~foo.m_a = " << m_a << "\n";
std::cout << this << "->foo::~foo.m_b = " << m_b << "\n";
}
};
int main()
{
{
// create some memory on the stack
ct_local_mem<4096> local = { '\0' };
// create a foo f
std::cout << "Naturally aligned...\n";
foo* f = new (local.align_mem<foo>(alignof(foo))) foo(1, 2);
// destroy f
f->~foo();
// create a foo f aligned on a large byte boundary
std::size_t alignment = 2048;
std::cout << "\n\nForced aligned on a " << alignment << " byte
boundary...\n";
// ensure the alignment of foo is okay with the boundary
assert((alignment % alignof(foo)) == 0);
f = new (local.align_mem<foo>(alignment)) foo(3, 4);
assert(CT_RALLOC_ALIGN_ASSERT(f, alignment));
// destroy f
f->~foo();
}
{
std::cout << "\n\nFin\n";
std::cout.flush();
std::cin.get();
}
return 0;
}
______________________
Here is some output, notice the addresses on the large boundary:
______________________
Naturally aligned...
0x7fffb1f56ba0->foo::foo.m_a = 1
0x7fffb1f56ba0->foo::foo.m_b = 2
0x7fffb1f56ba0->foo::~foo.m_a = 1
0x7fffb1f56ba0->foo::~foo.m_b = 2
Forced aligned on a 2048 byte boundary...
0x7fffb1f57000->foo::foo.m_a = 3
0x7fffb1f57000->foo::foo.m_b = 4
0x7fffb1f57000->foo::~foo.m_a = 3
0x7fffb1f57000->foo::~foo.m_b = 4
______________________
Notice how the latter pointer values have zeros at the end? There are
many fun things we can do here, but I am afraid it all UB. ;^o