C ++的新操作是否保证地址返回的对齐?

时间:2009-02-03 09:44:04

标签: c++ performance alignment new-operator

大多数有经验的程序员都知道数据对齐对程序的性能很重要。我看到一些程序员编写的程序分配比他们需要的更大的缓冲区大小,并使用对齐的指针作为开始。我想知道我应该在我的程序中这样做,我不知道是否有任何保证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.似乎返回的新操作的所有地址都是对齐的。但我不确定。所以我的问题是:有保证吗?如果他们确实有保证,我不需要调整自己,如果没有,我必须。

6 个答案:

答案 0 :(得分:23)

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

  

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

编辑:感谢timday突出显示保证不存在的gcc / glibc中的bug

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

答案 1 :(得分:14)

这是一个迟到的答案,只是为了澄清Linux上的情况 - 在64位系统上 内存总是16字节对齐:

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

  

GNU系统中malloc或realloc返回的块的地址始终为a    八个中的多个(或64位系统上的十六个)。

new运算符在内部调用malloc (见./gcc/libstdc++-v3/libsupc++/new_op.cc) 所以这也适用于new

作为malloc一部分的glibc的实现基本上是定义的 MALLOC_ALIGNMENT 2*sizeof(size_t)size_t为32位= 4byte,64位= 8byte 分别在x86-32和x86-64系统上。

$ 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

答案 2 :(得分:7)

顺便说一下,MS documentation提到了一些关于malloc / new返回地址的信息,这些地址是16字节对齐的,但是从实验开始就不是这种情况。我碰巧需要一个项目的16字节对齐(以加快具有增强指令集的内存副本),最后我使用自己的分配器编写...

答案 3 :(得分:4)

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

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

答案 4 :(得分:4)

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

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

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

我认为这是一个特别讨厌的编码,这对于它自己的好处来说是非常聪明的!

答案 5 :(得分:4)

C ++ 17更改了对new分配器的要求,因此要求返回一个指针,其对齐方式等于宏__STDCPP_DEFAULT_NEW_ALIGNMENT__(由实现定义,而不是由包括标题)。

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

此外,请注意,如果您用自己的分配器覆盖默认的new,则必须遵守__STDCPP_DEFAULT_NEW_ALIGNMENT__