
作為一名C開發人員,在日常工作中碰到的最多的問題大概就是與內存相關的。例如內存泄露、指針異常、堆棧溢出等,今天所說的主題也是與內存相關的,在接下來的內容中,我們將詳細介紹memcpy和memmove在操作內存的區別,讓大家能更好地理解和應對這些常見的內存相關問題,從而編寫出更高質量的C代碼。
在使用一個UI庫提供的多行文本控件時,當修改數據時,數據會出現異常。多行文本控件可以理解成我們電腦中的記事本,不過只能做一些簡單的刪除修改操作。然后就開始會調試這個庫,監控數據在何時變化的,最終定位到是在調用memcpy出現了問題,先簡介下這個函數的作用。
void* memcpy( void* dest, const void* src, std::size_t count )memcpy在進行數據拷貝時,如果源地址和目的地址對應的內存中有部分空間是有重疊的,會導致數據異常。
假如下方為memcpy在進行數據拷貝時的內存空間示意圖:
??[--------src--------]
?????????????[--------dest--------]??????????
在進行內存拷貝時,源地址和目的地址對應的內存中有部分空間是有重疊的,當進行第一個字節的數據拷貝時,源地址中的dest地址數據也會遭到破壞,從而導致數據異常。
解決內存重疊的問題其實很簡單,memmove可以解決這個問題。
memmove簡介
void* memmove( void* dest, const void* src, std::size_t count )上網查找了一下Linux內核中這兩個函數的源碼,如下所示:
??599?void?*memcpy(void?*dest,?const?void?*src,?size_t?count)
??600?{
??601?????char?*tmp?=?dest;
??602?????const?char?*s?=?src;
??603?
??604?????while?(count--)
??605?????????*tmp++?=?*s++;
??606?????return?dest;
??607?}
分析memcpy源碼可知,memcpy內存拷貝時從低地址向高地址(從左往右)復制。
??620?void?*memmove(void?*dest,?const?void?*src,?size_t?count)
??621?{
??622?????char?*tmp;
??623?????const?char?*s;
??624?
??625?????if?(dest?<=?src)?{
??626?????????tmp?=?dest;
??627?????????s?=?src;
??628?????????while?(count--)
??629?????????????*tmp++?=?*s++;
??630?????}?else?{
??631?????????tmp?=?dest;
??632?????????tmp?+=?count;
??633?????????s?=?src;
??634?????????s?+=?count;
??635?????????while?(count--)
??636?????????????*--tmp?=?*--s;
??637?????}
??638?????return?dest;
??639?}
分析memmove源碼可知,當源地址大于等于目的地址時,如下所示:
??????????[--------src--------]
??[--------dest--------]????
從低地址向高地址(從左往右)復制,即使有內存重疊也不影響結果。
當源地址小于目的地址時,如下所示:
??[--------src--------]
?????????[--------dest--------]????
如果使用memcpy方法復制就會破壞源數據的正確性,所以需要從高地址向低地址(從右往左)復制。
我在網上搜集了幾個點:
https://docs.huihoo.com/doxygen/linux/kernel/3.7/lib_2string_8c_source.html
道理都懂了,您更傾向于使用哪一種內存拷貝函數?文末留言說出您的看法,讓我們一起探討!
END
點贊、轉發加關注,一鍵三連,好運年年
關注公眾號后臺回復數字688或668可獲取嵌入式相關資料
往期推薦
揭秘難以復現Bug的解決之道:堆棧分析實戰

加個變量,程序崩了

關于海明碼,我悟了

為什么C語言執行效率高,運行快?

