提问者:小点点

在堆栈上分配对齐的内存,如_alloca


_alloca()的留档是这样的:

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

然而,这里说:

_alloca需要16字节对齐,并且需要使用帧指针。

因此,在第一次引用中,他们似乎忘记了32字节对齐的AVX/AVX2类型,如__m256d

另一件让我困惑的事情是,第一页说_alloca()已弃用,而它建议使用一个可能从堆而不是堆栈分配内存的函数(这在我的多线程应用程序中是不可接受的)。

那么有人能告诉我是否有一些现代(也许是新的C/C标准?)对齐堆栈内存分配的方法吗?

澄清1:请不要提供要求数组大小为编译时常量的解决方案。我的函数根据运行时参数值分配可变数量的数组项。


共3个答案

匿名用户

使用_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的编译器也将允许新定义的类型。