• 2009-04-15

    简说GLIBC strncpy实现 - [语言探索]

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://bigwhite.blogbus.com/logs/37947818.html

    比较以下两组代码,你认为哪组运行的更快些呢?
    Example1:
            int n   = 100;
            int n4  = n >> 2;
            int i   = 0;

            int a[100];

            for (i = 0; i < n4 ;i += 4) {
                    a[i] = i;
                    a[i+1] = i+1;
                    a[i+2] = i+2;
                    a[i+3] = i+3;
            }

    Example2:
           for (i = 0;i < 100;i++) {
                 a[i] = i;
           }

    其实这个问题在"代码大全2nd"中也有讨论,从"代码大全"中的统计结果来看,一般来说Example1更占有优势。我在solaris上做了测试,在未开优化的情况下:两者运行时间分别为2ms和6ms;在打开-O2优化后,两者均为1ms。这种通过减少循环次数的方法在GLIBC中也有体现,比如说strncpy的实现:

    下面是strncpy的GLIBC源码:
    char *
    x_strncpy (s1, s2, n)
            char *s1;
            const char *s2;
            size_t n;
    {
            reg_char c;
            char *s = s1;

            --s1;

            if (n >= 4)
            {
                    size_t n4 = n >> 2; /* n4 = n / 4, n4表示下面的循环执行的次数*/

                    for (;;)
                    {
                            c = *s2++;
                            *++s1 = c;
                            if (c == '\0')
                                    break;
                            c = *s2++;
                            *++s1 = c;
                            if (c == '\0')
                                    break;
                            c = *s2++;
                            *++s1 = c;
                            if (c == '\0')
                                    break;
                            c = *s2++;
                            *++s1 = c;
                            if (c == '\0')
                                    break;
                            if (--n4 == 0)
                                    goto last_chars;  /* 如果n = 10,s2 = "hello world",则两轮循环后,还有"尾巴"没有copy完,在last_chars处继续处理 */
                    }
                    n = n - (s1 - s) - 1;  /* 还没有copy完n个字节,s2就到达末尾了,跳到zero_fill处继续为s1补零 */
                    if (n == 0)
           return s;
                    goto zero_fill;
            }

    last_chars:     
            n &= 3;       /* n = n & 3 结果 n <= 3,n即为上面循环过后"尾巴字符"的数量 */
            if (n == 0)
                    return s;
            do
            {
                    c = *s2++;
                    *++s1 = c;
                    if (--n == 0)
                            return s;
            } while (c != '\0');

    zero_fill:       
            do
                    *++s1 = '\0';
            while (--n > 0);

            return s;
    }

    相比于strlen的实现,strncpy的实现更易理解。其字面上的逻辑就是每四个字节(n>>2)作为一组,每组逐个字节进行拷贝赋值,其内在目的则是减少循环次数,以获得性能的提升。要想知道为什么减少循环次数能提升性能的话,那就要深入到汇编层面去了,这里不再详述。另外还要一提的是GLIBC中的strncmp,strncat的实现也遵循着与上面同样的逻辑。


    历史上的今天:


    收藏到:Del.icio.us




    引用地址:

    评论

  • 博主,我给你发的申请连接贴几天了,你怎么还没回复啊?我已经添加你链接几天了啊!!!最起码也要给点回音吧!
    回复myuu说:
    不好意思,我只给我自己喜欢的博客加链接,您的博客内容尚未丰富,对我来说还谈不上喜欢不喜欢,所以暂时还不会加你,希望你能理解。
    2009-05-02 19:58:09
  • 博主,做个链接好吗?您的我已做好了!
    畅赢天下
    http://getyoumoney.blogbus.com/