memcpy在编译时知道大小

时间:2015-06-19 11:08:20

标签: c++ performance memcpy

我发现自己调整了一段代码,其中使用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 ++编译器,或者是否有一些我遗漏的编译器标志?

2 个答案:

答案 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指令。

但是,您的源地址和目标地址不是此函数的参数,这似乎阻止了编译器进行这种积极的优化。