1. 程式人生 > >記憶體拷貝函式memmove(支援記憶體重疊拷貝)的實現

記憶體拷貝函式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 <iostream>
#include <cassert>
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; }

總結:
初寫程式碼的時候,往往考慮的是程式正常工作的情況該怎麼處理。當你有了幾年經驗,寫了幾萬行程式碼後就會發現,處理異常部分的分支程式碼有時比正常的主幹線程式碼還要多,而這也正是高質量程式和一般程式拉開差距的地方。如果把軟體產品當作一臺機器,那麼這樣一個個細小的函式和類就是零部件,只有當這些零部件質量都很高時,整個軟體產品的質量才會高,不然就會像前幾年的國產轎車一樣,今天這個零件罷工明天那個零件休息。而作為檢驗這些零部件的測試用例,一定要模擬各種惡劣的環境,將零部件隱藏的缺陷暴露出來,從這意義上說,編寫測試用例的程式設計師要比軟體設計的程式設計師思維要更嚴謹才行。