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

时间:2011-02-27 16:05:38

标签: c++ alignment

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

我正在尝试根据某些任意类型的对齐方式弄清楚如何在堆栈上对齐char缓冲区。理想情况下,代码会显示为:

__declspec( align( __alignof(MyType) ) ) char buffer[16*sizeof(MyType)];

不幸的是,这不起作用

  

错误C2059:语法错误:   '__builtin_alignof'

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

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

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

有谁知道更好的方式?看起来像declspec的东西应该有用,我只是语法错了还是什么?

感谢阅读:)

6 个答案:

答案 0 :(得分: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;

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

在上面的代码中,AlignedStorage<T>::data将是POD类型(MSVC和GCC中的char []数组),T和T * N的大小合适。

答案 1 :(得分:3)

你确定MyType是一个有效的整数幂吗?

__declspec( align( # ) ) declarator
  

#是对齐值。有效条目是2的整数幂   1到8192(字节),例如2,4,8,   16,32或64.声明者是数据   你宣布对齐。

- align (C++)

答案 2 :(得分: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;}
};

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

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;可以出现在代码中,但也可以作为更大类的成员(这就是我使用此hack的方式),并且在堆上分配时也应该正常运行。

错误修复:

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

答案 3 :(得分:1)

alloca()怎么样? (或者,更具体地说,对于MSVC2008,_malloca())?

  

在堆栈上分配内存。这是_alloca的一个版本,具有安全性增强功能,如CRT中的安全增强功能所述。

对齐行为在编译器之间没有标准化,但对于这个......

  

_malloca例程返回一个指向已分配空间的void指针,保证适当地对齐以存储任何类型的对象。

答案 4 :(得分:1)

有同样的问题。 您可以以安全的方式混合使用align__alignof的宏(哦恐怖):

// `align` und `__alignof` cannot be combined - hence this workaround where you also have to specify the alignment manually (but checked)
#define ALIGN_FOR_TYPE( TypeName, TypeAlignment )                           \
    const size_t ALIGN_FOR_TYPE_alignOf##TypeName = __alignof(TypeName);    \
    BOOST_STATIC_ASSERT(ALIGN_FOR_TYPE_alignOf##TypeName == TypeAlignment); \
    __declspec( align( TypeAlignment ) )                                    \
/**/

ALIGN_FOR_TYPE(MyStructType, 4) char StructBuffer[sizeof(MyStructType)];

答案 5 :(得分:0)

如果要在堆栈上声明对齐数据,则无需执行任何其他“黑客攻击”。编译器会处理这个问题。

如果您希望之后成为char数组,只需将其强制转换为char*

请尝试以下测试示例进行确认:

#include <stdio.h>

struct UnalignedX {
    int x;
};

__declspec(align(128)) struct AlignedX {
    int x;
};

int main() {
    UnalignedX arr[5];
    AlignedX aarr[5];
    printf("UnalignedX: %x %x\n",arr,arr+1);
    printf("AlignedX: %x %x\n",aarr,aarr+1);
    char *final=(char*)aarr; //this becomes the char array that you asked for
    return 0;
};

在我的电脑上,我得到了输出:

UnalignedX: 14fe68 14fe6c
AlignedX: 14fb80 14fc00

在堆上分配数据时,必须小心对齐(mallocnew

__declspec( align( N ))期望N是文字。它必须是数字,而不是函数调用。