This question is specific to the MSVC compiler (specifically 2008), but I'm interested in non-compiler specific answers too.
I'm trying to figure out how to align a char buffer on the stack, based on the alignment of some arbitrary type. Ideally the code would read:
__declspec( align( __alignof(MyType) ) ) char buffer[16*sizeof(MyType)];
Unfortunately, this doesn't work
error C2059: syntax error : '__builtin_alignof'
The compiler just doesn't like the nested statements.
My only other idea is to do this:
char buffer[16*sizeof(MyType)+__alignof(MyType)-1];
char * alignedBuffer = (char*)((((unsigned long)buffer) + __alignof(MyType)-1)&~(__alignof(MyType)-1));
Does anyone know of a nicer way? It seems like the declspec thing should work, do I just have the syntax wrong or something?
Thanks for reading :)
So to align something in memory means to rearrange data (usually through padding) so that the desired item's address will have enough zero bytes.
Stack is word aligned. So, if this is the only variable, the compiler would have to do special work to make the variable non word-aligned. You can look at the dissasembly and see how it is allocated upon the entry into the function.
Alignment is limiting addresses where data can be placed and is not limited to stacks. For example, 4-byte alignment would mean that all addresses have the lowest 2 bits always 0. The alignment often corresponds to the memory bus width in the hardware which can be several bytes wide.
You can use std::aligned_storage
together with std::alignment_of
as an alternative.
#include <type_traits>
template <class T, int N>
struct AlignedStorage
{
typename std::aligned_storage<sizeof(T) * N, std::alignment_of<T>::value>::type data;
};
AlignedStorage<int, 16> myValue;
This is supported by MSVC 2008 and up. If you need portability to other non-C++11 compilers you can use std::tr1::aligned_storage
and std::tr1::alignment_of
and the <tr1/type_traits>
header.
In the above code, AlignedStorage<T>::data
will be a POD type (a char[] array in MSVC and GCC) of a suitable alignment for T and size T*N.
Update
Check Robert Knight's answer! Uses C++11 but is much cleaner than this...
Original Answer
How about this nasty hack:
namespace priv {
#define PRIVATE_STATICMEM(_A_) \
template <size_t size> \
struct StaticMem<size,_A_> { \
__declspec(align(_A_)) char data[size]; \
void *operator new(size_t parSize) { \
return _aligned_malloc(parSize,_A_); \
} \
void operator delete(void *ptr) { \
return _aligned_free(ptr); \
} \
};
template <size_t size, size_t align> struct StaticMem {};
template <size_t size> struct StaticMem<size,1> {char data[size];};
PRIVATE_STATICMEM(2)
PRIVATE_STATICMEM(4)
PRIVATE_STATICMEM(8)
PRIVATE_STATICMEM(16)
PRIVATE_STATICMEM(32)
PRIVATE_STATICMEM(64)
PRIVATE_STATICMEM(128)
PRIVATE_STATICMEM(256)
PRIVATE_STATICMEM(512)
PRIVATE_STATICMEM(1024)
PRIVATE_STATICMEM(2048)
PRIVATE_STATICMEM(4096)
PRIVATE_STATICMEM(8192)
}
template <typename T, size_t size> struct StaticMem : public priv::StaticMem<sizeof(T)*size,__alignof(T)> {
T *unhack() {return (T*)this;}
T &unhack(size_t idx) {return *(T*)(data+idx*sizeof(T));}
const T &unhack() const {return *(const T*)this;}
const T &unhack(size_t idx) const {return *(const T*)(data+idx*sizeof(T));}
StaticMem() {}
StaticMem(const T &init) {unhack()=init;}
};
Looks scary, but you need all that only once (preferably in some well hidden header file :) ). Then you can use it in the following way:
StaticMem<T,N> array; //allocate an uninitialized array of size N for type T
array.data //this is a raw char array
array.unhack() //this is a reference to first T object in the array
array.unhack(5) //reference to 5th T object in the array
StaticMem<T,N> array;
can appear in the code, but also as a member of some bigger class (that's how I use this hack) and should also behave correctly when allocated on the heap.
Bug fix:
Line 6 of the example: char data[_A_]
corrected into char data[size]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With