• memmove 和 memcpy的区别


    memcpy和memmove()都是C语言中的库函数,在头文件string.h中,作用是拷贝一定长度的内存的内容,原型分别如下:
    void *memcpy(void *dst, const void *src, size_t count);

    void *memmove(void *dst, const void *src, size_t count); 

    他们的作用是一样的,唯一的区别是,当内存发生局部重叠的时候,memmove保证拷贝的结果是正确的,memcpy不保证拷贝的结果的正确。


    第一种情况下,拷贝重叠的区域不会出现问题,内容均可以正确的被拷贝。
    第二种情况下,问题出现在
    右边的两个字节,这两个字节的原来的内容首先就被覆盖了而且没有保存。所以接下来拷贝的时候,拷贝的是已经被覆盖的内容,显然这是有问题的。
    实际上,
    memcpy只是memmove的一个子集

    二者的c语言实现很简单,有兴趣的朋友可以去看看。在实际情况下,这两个函数都是用汇编实现的。

    memmove在copy两个有重叠区域的内存时可以保证copy的正确,而memcopy就不行了,
    但memcopy比memmove的速度要快一些,如:
    char s[] = "1234567890";
    char* p1 = s;
    char* p2 = s+2;
    memcpy(p2, p1, 5)与memmove(p2, p1, 5)的结果就可能是不同的,memmove()可以将p1的头5个字符"12345"正确拷贝至p2,而memcpy()的结果就不一定正确了

    变态的命名

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

    先说memcpy

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

    复制代码 代码如下:

    void  *memcpy(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 *memmove(void *dest, const void *src, size_t count)
    {
    assert(dest != NULL || src != NULL)

    if (dst < 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)对应的情况时,就需要先从src的头部开始复制;也就是memmove源码中的if分支,这部分源码和memcpy的实现是一致的;当出现(2)对应的情况时,就需要先从src的尾部开始复制,防止出现了覆盖现象。这就是memmove比memcpy多的一个考虑点,所以说,在实际使用时,使用memmove是比memcpy更安全的。



     
  • 相关阅读:
    LinkedHashMap源码学习
    HashMap源码学习
    Java中"或"运算与"与"运算快慢的三三两两
    Java源码记录
    SpringBoot系列随笔
    分布式事物
    分布式事物
    部署spring boot + Vue遇到的坑(权限、刷新404、跨域、内存)
    一次使用存储过程游标遇到的坑
    UML简单介绍—类图详解
  • 原文地址:https://www.cnblogs.com/luoquan/p/5265273.html
Copyright © 2020-2023  润新知