我需要从某个内存位置将几个四字加在一起:
uint64_t sum2 (const char * p, size_t n)
{
uint64_t res = 0;
const uint32_t * q = (const uint32_t*) p;
size_t i;
for (i = 0; i < n; i++) res += q[i];
return res;
}
我知道这段代码不必在任意机器上的任意 C 编译器上工作。并非每个指向 char
的指针都可以转换为指向 int
的有效指针。但是,在 Intel 上,您可以从任何地址读取 32 位值,在大多数情况下甚至没有任何性能损失,因此这段代码应该可以正常工作,而不管 p
的对齐方式如何。我的程序在 64 位 Intel Sandy Bridge 上运行,使用 GCC 4.8 使用 -msse4.2 -O3
编译。
本地址不是 4 对齐时,此代码发出 SIGSEGV。原因是循环展开四次并使用 SSE 编译。使用MOVDQA一起读取四个值,需要16位对齐。在循环之前,指针16位对齐,前提是它已经4位对齐。
如何防止 GCC 上的 SSE 优化?我确实需要添加未对齐的 32 位数字。
最佳答案
它可能会降低性能,但我认为您需要使用 memcpy
复制到正确对齐的临时文件。
uint64_t sum2 (const char * p, size_t n)
{
uint64_t res = 0, temp;
const uint32_t * q = (const uint32_t*) p;
size_t i;
for (i = 0; i < n; i++) {
memcpy(&temp, &q[i], sizeof(*q));
res += temp;
}
return res;
}
希望它不会对齐 q
或 &q[i]
。如果是这种情况,您需要自己进行地址运算。
uint64_t sum2 (const char * p, size_t n)
{
uint64_t res = 0, temp;
size_t i;
for (i = 0; i < n; i++, p += sizeof(uint32_t)) {
memcpy(&temp, p, sizeof(uint32_t));
res += temp;
}
return res;
}
关于c++ - 英特尔 x64 的 GCC 中指向整数的指针对齐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39300708/