对齐堆栈上的数据(C++)

JBe*_*Fat 13 c++ alignment

这个问题特定于MSVC编译器(特别是2008),但我也对非编译器特定的答案感兴趣.

我试图弄清楚如何在堆栈上对齐char缓冲区,基于某些任意类型的对齐.理想情况下,代码将为:

__declspec( align( __alignof(MyType) ) ) char buffer[16*sizeof(MyType)];
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不起作用

错误C2059:语法错误:'__ builtin_alignof'

编译器只是不喜欢嵌套语句.

我唯一的另一个想法是这样做:

char buffer[16*sizeof(MyType)+__alignof(MyType)-1];
char * alignedBuffer = (char*)((((unsigned long)buffer) + __alignof(MyType)-1)&~(__alignof(MyType)-1));
Run Code Online (Sandbox Code Playgroud)

有谁知道更好的方式?似乎declspec的东西应该工作,我只是语法错误或什么?

谢谢阅读 :)

Rob*_*ght 5

您可以std::aligned_storagestd::alignment_of其他人一起使用.

#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;
Run Code Online (Sandbox Code Playgroud)

MSVC 2008及更高版本支持此功能.如果需要移植到其他非C++ 11个编译器可以使用std::tr1::aligned_storagestd::tr1::alignment_of<tr1/type_traits>头部.

在上面的代码中,AlignedStorage<T>::data将是POD类型(MSVC和GCC中的char []数组),其具有T和大小T*N的适当对齐.


Cyg*_*sX1 3

更新

检查罗伯特·奈特的答案!使用 C++11 但比这个干净得多......


原答案

这个令人讨厌的黑客怎么样:

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;}
};
Run Code Online (Sandbox Code Playgroud)

看起来很可怕,但你只需要一次(最好是在一些隐藏得很好的头文件中:))。然后您可以通过以下方式使用它:

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
Run Code Online (Sandbox Code Playgroud)

StaticMem<T,N> array;可以出现在代码中,但也可以作为某个更大类的成员(这就是我使用此技巧的方式),并且在堆上分配时也应该表现正确。

错误修复:

示例的第 6 行:char data[_A_]更正为char data[size]