如何在堆栈上对齐缓冲区

How can I align a buffer on the stack?

本文关键字:对齐 缓冲区 堆栈      更新时间:2023-10-16

我正在尝试实现一个按大小对齐的内存缓冲区,这样我就可以使用DMA控制器的模特性来实现环形缓冲区。我知道我可以用memalign来实现这一点,但我想知道是否可以在堆栈上实现,因为到目前为止,我已经能够避免动态内存。我使用的是GCC 4.4.1,我不关心可移植性(嵌入式系统)。

我想做一些类似的事情:

template<uint16_t num_channels, uint16_t buffer_size>
class sampler {
__attribute__((aligned(buffer_size * num_channels * 2)))
uint16_t buffer[buffer_size][num_channels];
};

但GCC当然不会接受非恒定排列(这似乎表明>8的排列可能无论如何都不会得到遵守)。

我想我可以使用C++0x alignas()来实现这一点,但它似乎直到4.8版本才出现在GCC中。

我想一种选择可能是将缓冲区的大小增加一倍,但这似乎浪费了大量空间(我正计划将设备内存的很大一部分用于这个缓冲区)。也许我应该放弃,使用动态记忆。memalign在浪费空间方面会相对高效吗?

有什么想法吗?

您不需要将存储的大小增加一倍,只需要将(alignment - 1)添加到其中——基本上与memalign在幕后所做的相同。对于二次方对齐:

char buf[size + (alignment -1)];
char *aligned = (char*)((intptr_t)buf + (alignment - 1) & ~intptr_t(alignment - 1));

我已经很久没有使用链接器命令文件了,但我认为会是这样。

使用创建文件buffer.cpp

char buffer[ BUFFER_SIZE ];

一个对象文件包含名为.bss(用于未初始化的数据)、.data(用于初始化数据)和.text(用于可执行代码)的部分。buffer[]将进入.bss,因为它尚未初始化。

因此,像这样的(gnu)链接器文件应该可以完成

SECTIONS {
.bss 0x0  : {
buffer.o(.bss)
*(.bss)
}
.data : {
*(.data)
}
.text : {
*(.text)
}
}

0x0告诉链接器加载地址为0x0的缓冲区[]。

您能创建一个大于buffer_size的缓冲区,然后计算其中的偏移量吗?

如果嵌入式系统有内存管理单元,那么就不必担心明智地使用动态内存,尤其是如果每次运行只分配一次。

如果它没有MMU,可以考虑使用链接器映射文件指定一个固定位置。

在具有实际操作系统的系统上,DMA兼容的缓冲区可能无论如何都必须由内核专门分配。