简说GLIBC strncpy实现

Tag: 语言探索

版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
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的实现也遵循着与上面同样的逻辑。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值