一个好奇的C语言字符串复制函数

9
当我阅读nginx代码时,我看到了这个函数:
#define ngx_cpymem(dst, src, n)   (((u_char *) memcpy(dst, src, n)) + (n))

static ngx_inline u_char *
ngx_copy(u_char *dst, u_char *src, size_t len)
{
    if (len < 17) {

        while (len) {
            *dst++ = *src++;
            len--;
        }

        return dst;

    } else {
        return ngx_cpymem(dst, src, len);
    }
}

这是一个简单的字符串复制函数。但为什么它会测试字符串的长度,如果长度大于等于17,则切换到memcpy函数呢?

为什么这个问题被标记为c++ - Lightness Races in Orbit
这其实不是一个字符串复制函数,而是一个内存复制函数。 - JeremyP
@Tomalak:IT不再是过去的IT了。 - JeremyP
1
有人应该建议nginx开发者在这里使用Duff's设备... :) - CAFxX
1个回答

12

这是一种优化方式——对于非常小的字符串,简单的复制比调用系统(libc)复制函数更快。

while 循环进行简单的复制对于短字符串而言速度相当快,并且系统复制函数通常针对长字符串进行了优化。但是系统复制还要执行很多检查和一些设置。

实际上,在这段代码之前,作者有一个注释:nginx,/src/core/ngx_string.h (搜索 ngx_copy)。

/*
 * the simple inline cycle copies the variable length strings up to 16
 * bytes faster than icc8 autodetecting _intel_fast_memcpy()
 */

此外,一个两行的上标是

#if ( __INTEL_COMPILER >= 800 )

作者进行了测试并得出结论,即ICC优化的memcopy会进行长时间的CPU检查以选择最优化的memcopy变体。 他发现手动复制16个字节比ICC最快的memcpy代码更快。

对于其他编译器,nginx直接使用ngx_cpymem(memcpy)。

#define ngx_copy                  ngx_cpymem

作者进行了一项关于不同大小的memcpy函数的研究:

/*
 * gcc3, msvc, and icc7 compile memcpy() to the inline "rep movs".
 * gcc3 compiles memcpy(d, s, 4) to the inline "mov"es.
 * icc8 compile memcpy(d, s, 4) to the inline "mov"es or XMM moves.
 */

2
很可能,我想这就是意图,程序员可能在他们的环境中对其进行了分析,但是否总是更快很难说。 - Chris Card
1
简单的复制操作使用 while 循环,不包含额外的检查,并且进行逐字节的复制。在汇编指令方面更短。 - osgx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接