歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux內核 >> Linux內核中memcpy和memmove函數的區別和實現

Linux內核中memcpy和memmove函數的區別和實現

日期:2017/3/1 9:56:40   编辑:Linux內核

Kernel version:2.6.32

CPU architecture:ARM

•memcpy是把src指向的對象中的size個字符拷貝到dest所指向的對象中,返回指向結果對象的指針.

•memmove也是把src指向的對象中的size個字符拷貝到dest所指向的對象中,返回指向結果對象的指針,但這兩個函數在處理內存區域重疊的方式不同.

注意memmove這個函數名稱中有"move"這個單詞,而實際上src處的數據仍然還在,並沒有真的被"移動"了!這個函數名稱有它的歷史原因,是因為有了memcpy函數後,發現這個函數有問題,又發明了另一個沒有問題的memcpy函數,但為了爆出兼容性依然保留了memcpy函數,而將新版本的memcpy函數改名為memmove函數.

內存重疊問題是指目的地址的內存空間的首地址,包含在源內存空間中,這兩段內存空間有了交集,因而在使用memcpy進行內存復制操作時,這段重疊的內存空間會被破壞.這種情況在應用程序級代碼中一般不會出現的,而在驅動或內核級代碼中要十分小心,盡量使用memmove函數.

memcpy對內存空間有要求的,dest和src所指向的內存空間不能重疊,否則復制的數據是錯誤的.下面具體講解一下這個錯誤是如何產生的.

如果內存空間布局入下圖所示:

src所指向的內存空間後面部分數據被新拷貝的數據給覆蓋了(也就是dest<=src+size).所以拷貝到最後,原來的數據肯定不是原來的數據,拷貝的數據也不是想要的數據,使用memcpy函數可以得到錯誤的結果.

再者,如果內存空間布局入下圖所示:

雖然原來的數據不再是原來的數據(dest+size>=src),但拷貝的數據是原來的數據,使用memcpy函數可以得到正確的結果.因此,在使用memcpy這個函數之前,還需要做一個判斷,如果dest<=src你才能使用這個函數不過完全沒有必要,你直接使用memmove函數就可以了.memmove在拷貝之前就做了一個判斷,如果dest <= src,就按照memcpy的思路拷貝,如果dest>src怎麼辦呢,看函數,它是從後面往前拷貝,這樣就能正確拷貝數據了.根據上面的分析,理解下面的代碼應該是一件很容易的事情.

551 #ifndef __HAVE_ARCH_MEMCPY
552 /**
553 * memcpy - Copy one area of memory to another
554 * @dest: Where to copy to
555 * @src: Where to copy from
556 * @count: The size of the area.
557 *
558 * You should not use this function to access IO space, use memcpy_toio()
559 * or memcpy_fromio() instead.
560 */
561 void *memcpy(void *dest, const void *src, size_t count)
562 {
563 char *tmp = dest;
564 const char *s = src;
565
566 while (count--)
567 *tmp++ = *s++;
568 return dest;
569 }
570 EXPORT_SYMBOL(memcpy);
571 #endif
572
573 #ifndef __HAVE_ARCH_MEMMOVE
574 /**
575 * memmove - Copy one area of memory to another
576 * @dest: Where to copy to
577 * @src: Where to copy from
578 * @count: The size of the area.
579 *
580 * Unlike memcpy(), memmove() copes with overlapping areas.
581 */
582 void *memmove(void *dest, const void *src, size_t count)
583 {
584 char *tmp;
585 const char *s;
586
587 if (dest <= src) {
588 tmp = dest;
589 s = src;
590 while (count--)
591 *tmp++ = *s++;
592 } else {
593 tmp = dest;
594 tmp += count;
595 s = src;
596 s += count;
597 while (count--)
598 *--tmp = *--s;
599 }
600 return dest;
601 }
602 EXPORT_SYMBOL(memmove);
603 #endif

Copyright © Linux教程網 All Rights Reserved