内存拷贝函数memmove(支持内存重叠拷贝)的实现

主要考虑的情况如下:

1、拷贝的数据是任意类型数据,所以指针用void * 接收。

2、src源数据一般是只读的,在函数内部对其修改是非法的。

3、返回值类型是void *,主要用来实现链式表达式,就像赋值表达式一样。

4、判断指针是否为NULL时用assert而不是用if条件语句,因为每次调用函数都会进行一次判断,性能损失较大。
因此我们可以利用宏的开关作用。如果在调试时我们加入“#define DEBUG”语句,增强程序的健壮性,那么在调试通过后我们再改为“#undef DEBUG”语句,提高程序的性能。事实上在标准库里已经存在类似功能的宏:assert,而且更加好用,它还可以在定义DEBUG时指出代码在那一行检查失败,而在没有定义DEBUG时完全可以把它当作不存在。

5、考虑内存重叠的发生,即源地址区间和目的地址区间有重叠的地方。
1)dst <= src || (char )dst >= ((char )src + count
2)dst > src

#include 
#include 
using namespace std;

void* MyMemcpy(void* dst, const void* src, int count)
{
    assert(dst);
    assert(src);
    void* ret = dst;

    //考虑内存重叠
    if (dst <= src || (char*)dst >= ((char*)src + count))
    {
        while (count--)
        {
            *(char*)dst = *(char*)src;
            dst = (char*)dst + 1;
            src = (char*)src + 1;
        }
    }
    else
    {
    //  ret = (char*)src;//保证ret与dst一致
        dst = (char*)dst + count - 1;
        src = (char*)src + count - 1;
        while (count--)
        {
            *(char*)dst = *(char*)src;
            dst = (char*)dst - 1;
            src = (char*)src - 1;
        }
    }

    return ret;
}

int main()
{
    char p1[256] = "hello world!";
    char p2[256] = {0};

//  MyMemcpy(p2, p1, strlen(p1) + 1);
//  cout << p2 << endl;

//  MyMemcpy(NULL, p1, strlen(p1) + 1);

//  MyMemcpy(p2, NULL, strlen(p1) + 1);

//  MyMemcpy(p1, p1+1, strlen(p1) + 1);
//  cout << p1 << endl;

    char* ptr = (char*)MyMemcpy(p1+1, p1, strlen(p1) + 1);
    cout << p1 << endl;
    cout << ptr << endl;

    return 0;
}

总结:
初写代码的时候,往往考虑的是程序正常工作的情况该怎么处理。当你有了几年经验,写了几万行代码后就会发现,处理异常部分的分支代码有时比正常的主干线代码还要多,而这也正是高质量程序和一般程序拉开差距的地方。如果把软件产品当作一台机器,那么这样一个个细小的函数和类就是零部件,只有当这些零部件质量都很高时,整个软件产品的质量才会高,不然就会像前几年的国产轿车一样,今天这个零件罢工明天那个零件休息。而作为检验这些零部件的测试用例,一定要模拟各种恶劣的环境,将零部件隐藏的缺陷暴露出来,从这意义上说,编写测试用例的程序员要比软件设计的程序员思维要更严谨才行。

你可能感兴趣的:(C语言)