• memcpy()函数实现


    1.为什么会写memcpy

    笔试中遇到过一道笔试题,题目要求实现一个my_memcpy函数。函数原型:void * my_memcpy(void *dst, const void *src, int n); 函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源src中拷贝n个字节到目标dst中。

    之前使用的内存拷贝函数是标准库memcpy函数,拿来就用。当你自己在实现过程中,了解的越多,实现起来就越麻烦。

    2.按字节(Byte)拷贝实现的memcpy

    • 不考虑写覆盖,简单粗暴:
    void* my_memcpy_byte(void* dst, const void* src, size_t n) {
        // Copies n bytes from src to dst
         
        // Since we cannot dereference a void* ptr,
        // we first typecast it to a char* ptr
        // and then do the copying byte by byte,
        // since a char* ptr references a single byte
        char* char_dst = (char*) dst;
        char* char_src = (char*) src;
     
        for (int i=0; i<n; i++) {
            *char_dst++ = *char_src++;
        }
     
        return dst;
    }
    
    • 考虑写覆盖:
    void *my_memcpy_byte(void *dst, const void *src, int n)
    {
        if (dst == NULL || src == NULL || n <= 0)
            return NULL;
    
        char * pdst = (char *)dst;
        char * psrc = (char *)src;
    
        if (pdst > psrc && pdst < psrc + n)
        {
            pdst = pdst + n - 1;
            psrc = psrc + n - 1;
            while (n--)
                *pdst-- = *psrc--;
        }
        else
        {
            while (n--)
                *pdst++ = *psrc++;
        }
        return dst;
    }    
    //*pdst-- = *psrc--;  查了下运算符优先级(*,--)优先级相同,从右向左结合,psrc--是先使用,后减减    
    //等价于*pdst = *psrc;psrc--;pdst--;
    

    3.按4字节拷贝实现的memcpy

     

     void *my_memcpy(void *dst, const void *src, int n)
     {
     if (dst == NULL || src == NULL || n <= 0)
     return NULL;

     int * pdst = (int *)dst;
     int * psrc = (int *)src;
     char *tmp1 = NULL;
     char *tmp2 = NULL;
     int c1 = n / 4;
     int c2 = n % 4;
     
     /*if (pdst > psrc && pdst < psrc + n) 这样判断有问题*/
     if (pdst > psrc && pdst < (char *)psrc + n)
     {
     tmp1 = (char *)pdst + n - 1;
     tmp2 = (char *)psrc + n - 1;
     while(c2--)
     *tmp1-- = *tmp2--;
     /*这样有问题,忘记字节偏移
     pdst = (int *)tmp1;
     psrc = (int *)tmp2;
     */
     tmp1++;tmp2++;
     pdst = (int *)tmp1;
     psrc = (int *)tmp2;
     pdst--;psrc--;
     while (c1--)
     *pdst-- = *psrc--;
     }
     else
     {
     while (c1--)
     *pdst++ = *psrc++;3536 tmp1 = (char *)pdst;
     tmp2 = (char *)psrc;
     while (c2--)
     *tmp1++ = *tmp2++;
     }
     return dst;
    }      

    //备注:void *dst, const void *src这两个参数是需要按4字节对齐的,如果本身不是4字节对齐,按4字节拷贝效率也会变低。

    这里还是考虑了写覆盖的代码。对比按字节拷贝,拷贝速度是提高不少。

    以上是针对笔试过程中写memcpy。

    4.如何优化memcpy

    高性能的memcpy与很多因数相关,与平台,处理器,编译器,具体拷贝情形等相关。

    VS2017中对C库的memcpy进行优化,glibc对memcpy也有优化

    参考:怎样写出一个更快的 memset/memcpy ?

    5.是否需要考虑内存对齐拷贝?

    内存读写效率影响之一:内存对齐

    参考:1.浅谈CPU内存访问要求对齐的原因     2.解析内存对齐

    如果src,dst的地址是不对齐的,读写效率变低。

    通过代码实现不对齐的拷贝,memcpy的实现会变得复杂,反而影响拷贝效率。

    这种不对齐情况我们可以预先避免,因为编译器在给我们分配空间时是按照内存对齐进行分配的

    6.根据拷贝数据大小进行优化

    1.多次调用memcpy,而每次拷贝数据大小Kb下的小拷贝

      这种情况下尽量减少分支预测,代码精简。

    2.拷贝Mb的memcpy实现

      这种情况影响拷贝效率主要在寻址上。

    参考:闲着没事测了一下memcpy

    参考:

    实现memcpy()函数及过程总结

      

  • 相关阅读:
    运维人员如何最大限度避免误删除文件
    制作U盘启动安装CentOS Linux系统
    VMware克隆虚拟机后无法启动网卡
    由SecureCRT命令行快捷键谈学习思想
    SecureCRT同时发送命令到所有主机
    Linux下rz/sz安装及使用方法
    Linux下seq的使用
    linux tail命令的使用方法详解
    删除一个目录下的所有文件,但保留一个指定文件
    java基础知识回顾之java Thread类学习(十一)--join方法的理解
  • 原文地址:https://www.cnblogs.com/carsonzhu/p/13668707.html
Copyright © 2020-2023  润新知