这个问题特定于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的东西应该有用,我只是语法错了还是什么?
感谢阅读:)
答案 0 :(得分:5)
您可以将std::aligned_storage
与std::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_storage
和std::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.声明者是数据 你宣布对齐。
答案 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
在堆上分配数据时,必须小心对齐(malloc
或new
)
__declspec( align( N ))
期望N是文字。它必须是数字,而不是函数调用。