31

大多数有经验的程序员都知道数据对齐对程序的性能很重要。我见过一些程序员编写的程序分配了比他们需要的更大的缓冲区,并使用对齐的指针作为开始。我想知道我是否应该在我的程序中这样做,我不知道 C++ 的新操作返回的地址是否对齐有任何保证。所以我写了一个小程序来测试

for(size_t i = 0; i < 100; ++i) {
    char *p = new char[123];
    if(reinterpret_cast<size_t>(p) % 4) {
        cout << "*";
        system("pause");
    }
    cout << reinterpret_cast<void *>(p) << endl;
}
for(size_t i = 0; i < 100; ++i) {
    short *p = new short[123];
    if(reinterpret_cast<size_t>(p) % 4) {
        cout << "*";
        system("pause");
    }
    cout << reinterpret_cast<void *>(p) << endl;
}
for(size_t i = 0; i < 100; ++i) {
    float *p = new float[123];
    if(reinterpret_cast<size_t>(p) % 4) {
        cout << "*";
        system("pause");
    }
    cout << reinterpret_cast<void *>(p) << endl;
}
system("pause");

我使用的编译器是 Visual C++ Express 2008。似乎新操作返回的所有地址都是对齐的。但我不确定。所以我的问题是:有任何保证吗?如果他们有保证,我不必调整自己,如果没有,我必须。

4

6 回答 6

27

对齐具有来自标准 (3.7.3.1/2) 的以下保证:

返回的指针应适当对齐,以便它可以转换为任何完整对象类型的指针,然后用于访问已分配存储中的对象或数组(直到通过调用相应的释放函数显式释放存储) .

编辑:感谢timday强调gcc/glibc 中的一个保证不成立的错误。

编辑 2:本的评论突出了一个有趣的边缘案例。分配程序的要求仅适用于标准提供的要求。如果应用程序有自己的版本,那么结果就没有这样的保证。

于 2009-02-03T10:09:40.457 回答
17

这是一个较晚的答案,但只是为了澄清 Linux 上的情况 - 在 64 位系统上,内存始终是 16 字节对齐的:

http://www.gnu.org/software/libc/manual/html_node/Aligned-Memory-Blocks.html

在 GNU 系统中 malloc 或 realloc 返回的块的地址始终是 8 的倍数(或 64 位系统上的 16)。

操作员在内部new调用malloc(请参阅./gcc/libstdc++-v3/libsupc++/new_op.cc),因此这也适用new

其实现malloc是x86-32 和 x86-64 系统上glibc基本定义 MALLOC_ALIGNMENT为32bit=4byte2*sizeof(size_t)size_t64bit=8byte 的一部分。

$ cat ./glibc-2.14/malloc/malloc.c:
...
#ifndef INTERNAL_SIZE_T
#define INTERNAL_SIZE_T size_t
#endif
...
#define SIZE_SZ                (sizeof(INTERNAL_SIZE_T))
...
#ifndef MALLOC_ALIGNMENT
#define MALLOC_ALIGNMENT       (2 * SIZE_SZ)
#endif
于 2012-05-16T21:47:31.293 回答
10

C++17 更改了对new分配器的要求,因此它需要返回一个对齐等于宏的指针__STDCPP_DEFAULT_NEW_ALIGNMENT__(由实现定义,而不是包含头文件)。

这很重要,因为这个大小可以大于alignof(std::max_align_t)例如,在 Visual C++ 中,最大常规对齐是 8 字节,但默认new总是返回 16 字节对齐的内存。

另外,请注意,如果您new使用自己的分配器覆盖默认值,您也需要遵守__STDCPP_DEFAULT_NEW_ALIGNMENT__

于 2019-07-31T17:45:25.710 回答
8

顺便说一句,MS 文档提到了一些关于 malloc/new 返回地址的内容,这些地址是 16 字节对齐的,但从实验来看,情况并非如此。我碰巧需要一个项目的 16 字节对齐(以通过增强的指令集加速内存复制),最后我求助于编写自己的分配器......

于 2009-02-03T12:11:37.187 回答
5

平台的 new/new[] 运算符将返回具有足够对齐的指针,以便它在基本数据类型(double、float 等)中表现良好。至少任何明智的 C++ 编译器+运行时都应该这样做。

如果您对 SSE 有特殊的对齐要求,那么使用特殊的 aligned_malloc 函数可能是个好主意,或者自己动手。

于 2009-02-03T10:28:44.680 回答
4

我在一个系统上工作,他们使用对齐来释放奇数位供自己使用!

他们使用奇数位来实现虚拟内存系统。

当一个指针设置了奇数位时,他们用它来表示它指向(减去奇数位)从数据库中获取数据而不是数据本身的信息。

我认为这是一种特别讨厌的编码,为了它自己的利益,它远非聪明!

托尼

于 2009-02-03T11:12:29.800 回答