我发现自己调整了一段代码,其中使用memcpy
复制内存,第三个参数(大小)在编译时是已知的。
调用memcpy
的函数的使用者执行与此类似的操作:
template <size_t S>
void foo() {
void* dstMemory = whateverA
void* srcMemory = whateverB
memcpy(dstMemory, srcMemory, S)
}
现在,我原本期望memcpy
内在足够聪明,可以意识到这一点:
foo<4>()
...可以用32位整数赋值替换函数中的memcpy
。但是,我惊讶地发现自己看到了> 2倍的加速:
template<size_t size>
inline void memcpy_fixed(void* dst, const void* src) {
memcpy(dst, src, size);
}
template<>
inline void memcpy_fixed<4>(void* dst, const void* src) { *((uint32_t*)dst) = *((uint32_t*)src); }
并将foo
重写为:
template <size_t S>
void foo() {
void* dstMemory = whateverA
void* srcMemory = whateverB
memcpy_fixed<S>(dstMemory, srcMemory)
}
两个测试都在clang(OS X)和-O3上进行。我真的希望memcpy
内在函数在编译时知道大小的情况下更聪明。
我的编译器标志是:
-gline-tables-only -O3 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer
我是否过多地询问了c ++编译器,或者是否有一些我遗漏的编译器标志?
答案 0 :(得分:5)
memcpy
与*((uint32_t*)dst) = *((uint32_t*)src)
不同。
memcpy可以处理未对齐的内存。
顺便说一下,大多数现代编译器都用适当的代码发射替换已知大小的memcpy。对于小尺寸,它通常会发出像rep movsb
这样的东西,在大多数情况下这可能不是最快的。
如果你发现你的特殊情况你获得了2倍的速度并且你认为你需要加快速度,那么你可以自由地弄脏你的手(有清晰的评论)。
答案 1 :(得分:1)
如果源缓冲区和目标缓冲区都作为函数参数提供:
template <size_t S>
void foo(char* dst, const char* src) {
memcpy(dst, src, S);
}
然后clang ++ 3.5.0仅在memcpy
较大时使用S
但在movl
时使用S = 4
指令。
但是,您的源地址和目标地址不是此函数的参数,这似乎阻止了编译器进行这种积极的优化。