_alloca()
的留档是这样的:
_alloca例程返回一个指向分配空间的void指针,该指针保证适当对齐以存储任何类型的对象。
然而,这里说:
_alloca需要16字节对齐,并且需要使用帧指针。
因此,在第一次引用中,他们似乎忘记了32字节对齐的AVX/AVX2类型,如__m256d
。
另一件让我困惑的事情是,第一页说_alloca()
已弃用,而它建议使用一个可能从堆而不是堆栈分配内存的函数(这在我的多线程应用程序中是不可接受的)。
那么有人能告诉我是否有一些现代(也许是新的C/C标准?)对齐堆栈内存分配的方法吗?
澄清1:请不要提供要求数组大小为编译时常量的解决方案。我的函数根据运行时参数值分配可变数量的数组项。
使用_alloca()过度分配,然后手动对齐。像这样:
const int align = 32;
void *p =_alloca(n + align - 1);
__m256d *pm = (__m256d *)((((int_ptr_t)p + align - 1) / align) * align);
如有必要,将const
替换为#定义
。
_alloca()
当然不是处理堆栈对齐的标准或可移植方式。幸运的是,在C 11中,我们得到了对齐
和std::aligned_storage
。这两种方法都不会强制您将任何东西放在堆上,因此它们应该适用于您的用例。例如,将结构数组对齐到32字节的边界:
#include <type_traits>
struct bar { int member; /*...*/ };
void fun() {
std::aligned_storage<sizeof(bar), 32>::type array[16];
auto bar_array = reinterpret_cast<bar*>(array);
}
或者,如果您只想将堆栈上的单个变量对齐到边界:
void bun() {
alignas(32) bar b;
}
您还可以使用对齐
运算符来获取给定类型的对齐要求。
C 11引入了对齐
运算符:
对齐表达式产生其操作数类型的对齐要求。
您可以按如下方式使用它:
struct s {};
typedef s __attribute__ ((aligned (64))) aligned_s;
std::cout << alignof(aligned_s); // Outputs: 64
注意:如果您的类型的对齐方式大于它的大小,编译器不会让您声明数组类型的数组(在此处查看更多信息):
错误:数组元素的对齐方式大于元素大小
但是,如果您的类型的对齐方式小于它的大小,您可以安全地分配数组:
aligned_s arr[32];
-- OR --
constexpr size_t arr_size = 32;
aligned_s arr[arr_size];
支持VLA的编译器也将允许新定义的类型。