C++ 对未对齐数据的操作速度

C++ 对未对齐数据的操作速度,c++,memory-alignment,C++,Memory Alignment,据我所知,CPU在边界上对齐的基准与该基准的大小相等时性能最佳。例如,如果每个int数据的大小为4字节,则每个int的地址必须是4的倍数,以使CPU满意;与2字节short数据和8字节double数据相同。因此,new运算符和malloc函数总是返回8的倍数,因此是4和2的倍数 在我的程序中,一些用于处理大字节数组的时间关键型算法允许通过将每个连续的4个字节转换为无符号int来跨越计算过程,并且通过这种方式,运算速度要快得多。但是,字节数组的地址不能保证为4的倍数,因为可能只需要处理字节数组的一

据我所知,CPU在边界上对齐的基准与该基准的大小相等时性能最佳。例如,如果每个
int
数据的大小为4字节,则每个
int
的地址必须是4的倍数,以使CPU满意;与2字节
short
数据和8字节
double
数据相同。因此,
new
运算符和
malloc
函数总是返回8的倍数,因此是4和2的倍数

在我的程序中,一些用于处理大字节数组的时间关键型算法允许通过将每个连续的4个字节转换为
无符号int
来跨越计算过程,并且通过这种方式,运算速度要快得多。但是,字节数组的地址不能保证为4的倍数,因为可能只需要处理字节数组的一部分

据我所知,Intel CPU可以正确地处理未对齐的数据,但会以牺牲速度为代价。如果对未对齐数据的操作速度足够慢,则需要重新设计程序中的算法。在这方面,我有两个问题,第一个问题由以下代码支持:

// the address of array0 is a multiple of 4:
unsigned char* array0 = new unsigned char[4];
array0[0] = 0x00;
array0[1] = 0x11;
array0[2] = 0x22;
array0[3] = 0x33;
// the address of array1 is a multiple of 4 too:
unsigned char* array1 = new unsigned char[5];
array1[0] = 0x00;
array1[1] = 0x00;
array1[2] = 0x11;
array1[3] = 0x22;
array1[4] = 0x33;
// OP1: the address of the 1st operand is a multiple of 4,
// which is optimal for an unsigned int:
unsigned int anUInt0 = *((unsigned int*)array0) + 1234;
// OP2: the address of the 1st operand is not a multiple of 4:
unsigned int anUInt1 = *((unsigned int*)(array1 + 1)) + 1234;
因此,问题是:

  • 在x86、x86-64和安腾处理器上,OP2比OP1慢多少(如果忽略类型转换和地址增量的成本)

  • 在编写跨平台的可移植代码时,对于未对齐的数据访问,我应该关注哪些类型的处理器?(我已经知道RISC的情况)


  • 市场上的处理器太多,无法给出一个通用的答案。唯一可以肯定的是,一些处理器根本无法进行未对齐的访问;如果您的程序打算在同质环境(例如Windows)中运行,则这可能对您来说很重要,也可能不重要

    在现代高速处理器中,未对齐访问的速度受其缓存对齐的影响可能大于其地址对齐的影响。在今天的x86处理器上,缓存线大小为64字节


    维基百科的一篇文章可能会提供一些一般性的指导:

    你不能用一个简单的循环来回答你自己的问题1吗?@Blindy-OP可能无法访问具有这些架构的处理器。在真正的可移植代码中,甚至
    anUInt1
    的计算可能会失败,导致未定义的行为。在某些正常的、当前的平台上,对未对齐数据的内存访问将引发异常,并可能终止您的进程(至少是SPARC)。这在这里不能得到充分的回答。您需要测试、配置文件等。处理器必须获得两个字,可能有两个缓存故障(许多体系结构处理双重故障的能力很差),然后根据需要屏蔽/旋转这些字(可能需要几个ALU周期)。在“拼接”第二个值时,需要一个额外的内部寄存器来保存第二个值,而且该寄存器通常不容易访问,需要多个周期来加载或存储。很多复杂的逻辑,很多设计师都不愿意花盖茨来超高效地完成这项工作,如果它足够罕见的话。