zoukankan      html  css  js  c++  java
  • memcpy和memmove

    变态的命名

          我们在写程序时,一般讲究见到变量的命名,就能让别人基本知道该变量的含义。memcpy内存拷贝,没有问题;memmove,内存移动?错,如果这样理解的话,那么这篇文章你就必须要好好看看了,memmove还是内存拷贝。那么既然memcpy和memmove二者都是内存拷贝,那二者究竟有什么区别呢?

    先说memcpy

          你有没有好好的参加过一场C++笔试。让你写出memcpy的实现,这是多么常见的笔试题啊。现在,拿起你的演算纸和笔;是的,是笔和纸,不是让你在你的IDE上写。写不出来?看下面吧:

    void *mymemcpy(void *dest, const void *src, size_t count)
    {
        assert(dest != NULL && src != NULL);
    
        char *tmp = (char *)dest;
        char *p = (char *)src;
    
        while (count--)
        {
            *tmp++ = *p++;
        }
        return dest;
    }

    memcpy的实现很简单,一般在笔试时,出现写源码的题目,无非就是需要注意以下几点:

    1. 确定函数原型;
    2. 判断参数合法性;
    3. 逻辑实现(考虑各种情况,统称逻辑实现);
    4. 错误处理。

    当然了,我的这个没有错误处理,也不需要错误处理。上面,我写出了memcpy的实现源码,实现原理如下图所示:
    果冻想 | 一个原创文章分享网站

    这样下去,上面的代码会运行的很好,如果出现下面的情况呢?
    果冻想 | 一个原创文章分享网站

    i、n、k的内存和J、e、l的内存地址重合了,现在再使用上面的代码进行copy时,会出现什么问题呢?你有没有想过这个问题。如果没有,那就现在想想,不急着阅读下面的内容。

    然后,我再留一个问题,上面的代码中,为什么都需要将void *转换成char *呢?比如:

    char *tmp = (char *)dest;

    可以留言回答哦。

    再说memmove

    memmove也是用来实现内存的直接拷贝的。说起这个命名,我个人觉的多少还是有点坑的。既然memmove也是用来内存数据移动的,那就先来看看memmove的实现源码。

    void *mymemmove(void *dest, const void *src, size_t count)
    {
        assert(dest != NULL && src != NULL);
    
        if (dest < src)   //当目的地址小于源地址时,情况一,从源地址的头部开始复制
        {
            char *p = (char *)dest;
            char *q = (char *)src;
            while (count--)
            {
                *p++ = *q++;
            }
        }
        else     //当
        {
            char *p = (char *)dest + count;
            char *q = (char *)src + count;
            while (count--)
            {
                *--p = *--q;
            }
        }
    
        return dest;
    }

    从源码看,memmove的确比memcpy复杂一些;再仔细一看,多了些什么?哦,多了一个else分支,而正是这个else分支,就处理了当src和dest的内存重合的问题。

    memcpy和memmove的比较

    从实现源码中的确能看出一些猫腻,当出现了src和dest的内存有重合的时机时,memmove的处理规则是从后往前进行copy。当然了,重合的问题,需要考虑的以下两种场合。
    果冻想 | 一个原创文章分享网站

    如图所示,

    当出现(1)对应的情况时,即:dest<src; 就需要先从src的头部开始复制;也就是memmove源码中的if分支,这部分源码和memcpy的实现是一致的;

    当出现(2)对应的情况时,即:dest>src; 就需要先从src的尾部开始复制,防止出现了覆盖现象。这就是memmove比memcpy多的一个考虑点,所以说,在实际使用时,使用memmove是比memcpy更安全的。

  • 相关阅读:
    ASCII码详解
    C#中判断上传类型为Excel,03和07版的链接字符串
    文本搜索工具的制作过程之搜索
    文本搜索工具之显示
    用C#实现十六进制字符串转换为ASCII
    7个秘诀 工作效率和薪水都翻倍
    C#委托
    VB的写法,关于版本写入注册表
    k8s 集群灾难恢复 k8s
    k8s 接合阿里云负载均衡 k8s
  • 原文地址:https://www.cnblogs.com/ranjiewen/p/5550085.html
Copyright © 2011-2022 走看看