memcpy的实现

来源:互联网 发布:java rest api是什么 编辑:程序博客网 时间:2024/05/18 01:45

我们平时经常用memcpy以及strcpy等等库函数,都知道用法,但是知道他们的区别吗?因此,从本文开始,将会探究一下他们的内部实现以及之间的区别。

google一下memcpy我们可以在http://www.cplusplus.com/reference/cstring/memcpy/找到关于memcpy的介绍,如下所示

memcpy

<cstring>

void * memcpy ( void* destination, const void * source, size_t num );

Copy block of memory

Copies the values of num bytesfrom the location pointed by source directly to the memoryblock pointed bydestination.

The underlying type of the objects pointed by both the source and destination pointersare irrelevant for this function; The result is a binary copy of the data.

The function does not check for any terminating nullcharacter in source - it always copies exactly num bytes.

To avoid overflows, the size of the arrays pointed by both the destination and source parameters,shall be at leastnum bytes, and should not overlap (for overlapping memory blocks, memmove isa safer approach).

从上面关于memcpy的介绍中我们可以得到以下三点信息

1、从memcpy的函数原型可以发现,其可以操作任意类型的数据

2、memcpy不会检测NULL字符,它会准确的拷贝num个字节的数据

3、使用该函数需要避免数据溢出,以及不要覆盖

我么了解了memcpy的以上特点以后,下面看看memcpy是如何实现的,如下面代码所示

void *memcpy(void *dest, void *src, unsigned long len){        unsigned long i;        if ((unsigned long)dest%sizeof(long) == 0 && \                (unsigned long)dest%sizeof(long) == 0 && \                (len%sizeof(long) == 0)) {                long *d = dest;                const long *s = src;                for (i=0; i<len/sizeof(long); i++) {                        d[i] = s[i];                }        }        else {                char *d = dest;                const char *s = src;                for (i=0; i<len; i++) {                        d[i] = s[i];                }        }        return dest;}

以上代码是memcpy的一个实现过程,其中最大的一个特点是,当目的地址(dest)、源地址(src)是四字节对齐,以及拷贝的个数是4的整数个的时候,可以采用每次拷贝4个字节的方式,这样即可以加速拷贝,节省了memcpy执行时间,提高效率

测试以上代码如下所示:

void test_memcpy(void){        struct timeval start_time;        struct timeval end_time;        long time_spent;        long i;        long dest[30000];        long src[30000];        for (i=0; i<20000; i++) {                src[i] = i;        }        gettimeofday (&start_time, NULL);        memcpy(dest, src, 20001);/* 此处设置为20001是为了采用1字节拷贝的,测试结果只是比4字节拷贝多拷贝了1个字节,没多大影响*/        gettimeofday (&end_time, NULL);        time_spent = (end_time.tv_sec - start_time.tv_sec)*1000000 + \                        (end_time.tv_usec - start_time.tv_usec); /* us */        printf("1 byte per time copy,  time_spent is %dus \n", time_spent);        gettimeofday (&start_time, NULL);        memcpy(dest, src, 20000);        gettimeofday (&end_time, NULL);        time_spent = (end_time.tv_sec - start_time.tv_sec)*1000000 + \                        (end_time.tv_usec - start_time.tv_usec); /* us */        printf("4 byte per time copy, time_spent is %dus \n", time_spent);}
采用以上代码,既可以测试出两种不同拷贝方式所花费的时间,从测试结果来看采用4字节拷贝方式效果是相当明显的,基本上是采用1个字节拷贝方式所花费时间的四分之一,测试结果如下所示:

以上4字节拷贝的方式中可以发现,4字节拷贝的确是有很大的优势? 但是以上设计中,要使用4字节拷贝却需要满足三个条件:第一、目的地址(dest)需要4字节对齐;第二、源地址(src)也需要四字节对齐;第三、拷贝个数需要是4的整数倍;如果不满足以上三个条件那么将会采用1字节方式进行拷贝。

因此,我们设想当不满足以上三个条件而拷贝字节数又是大于4个字节的内存块的时候,怎样采取4字节拷贝方式进行拷贝?

意外测试中发现,当采用linux内部的memcpy函数时,拷贝速度之快,如下图所示


因此,后面还需要详细分析linux里面memcpy函数的实现还是有相当必要的,此工作留到后面继续分析

查看linux内部memcpy的C语言实现,如下所示


原创粉丝点击