Aligning arrays

March 1, 2009 – 7:06 pm

When developing stack-based containers for RDESTL I’ve encountered the following problem – how to get block of uninitialized memory that’s aligned properly for type T. Consider fixed_vector class:

template<typename T, size_t N>
class fixed_array
{
...
char    m_data[N * sizeof(T)];

Size is OK (we need N elements of type T), sadly alignment is invalid here. It may not be a problem for majority of cases, but try storing _m128s… Even when using 32-bit variables, they should be aligned on natural boundary (4 bytess) in order to rely on writes/reads being atomic. Our first task — find out alignment of type T. In order to determine it, we create helper class with element of type T stored just after char, then get its offset:

template<typename T>
struct alignof_helper
{
char    x;
T       y;
};
template<typename T>
struct alignof
{
    enum
    {
        res = offsetof(alignof_helper<T>, y)
    };
};

Just to make sure it works (you may need to disable warning C4324 (structure was padded due to __declspec(align)) :

CHECK_EQUAL(16, rde::alignof<__m128>::res);

First part of a problem solved. However, “res” cannot be simply used as an argument to __declspec(align). Instead, we have to create basic types with most common alignments.

__declspec(align(16)) struct aligned16 { uint64_t member[2]; };
template<size_t N> struct type_with_alignment
{
    typedef char err_invalid_alignment[N > 0 ? -1 : 1];
};
template<> struct type_with_alignment<0> {};
template<> struct type_with_alignment<1> { uint8_t member; };
template<> struct type_with_alignment<2> { uint16_t member; };
template<> struct type_with_alignment<4> { uint32_t member; };
template<> struct type_with_alignment<8> { uint64_t member; };
template<> struct type_with_alignment<16> { aligned16 member; };

...

template<typename T>
struct aligned_as
{
    typedef typename internal::type_with_alignment<alignof<T>::res> res;
};

If necessary, some more types should be provided.

Finally, we create array of properly aligned types instead of chars. We also have to modify array size, as element size is no longer one byte, it needs to be corrected:

typedef typename aligned_as<T>::res    etype_t;
etype_t                    m_data[(N * sizeof(T)) / sizeof(etype_t)];

.

  1. 3 Responses to “Aligning arrays”

  2. I suppose you could use __alignof instead of this alignof_helper struct with offsetof.

    By Reg on Mar 8, 2009

  3. Sadly, __alignof isn’t really reliable: http://www.nabble.com/-Format–Asserts-with-non-default-structure-packing-in-1.37-(MSVC)-td21215959.html

    By admin on Mar 8, 2009

  1. 1 Trackback(s)

  2. Apr 5, 2010: jason gregory

Post a Comment