memcpy vs. memmove

這個事件是在工作中時間發生的案例。先看看下面的例子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    int a[100];
    int i = 0;
    int index = 5;
    
    for( i = 0 ; i < 100 ; i++ )
    {
        a[i] = i;
    }
    
    memcpy( &(a[index]), &(a[(index + 1)]), sizeof( int ) * ( 100 - index - 1 )  );
    
    for( i = 0 ; i < 100 ; i++ )
    {
        printf( "%d ", a[i] );
        
        if( ( i % 10 ) == 9 )
        {
            printf( "\n" );
        }
    }
    
    printf( "\n" );
    
    return 0;
}

好了,請問上面這段程式碼在寫什麼呢?

其實很簡單,這只是一個 array shift 的動作,將 index 後面的元素全部往前搬動一格。這樣寫會有什麼問題呢?我在我自己的電腦上什麼問題都沒有發生啊?

邏輯上很 OK ,但問題出在 memcpy 這隻函式上面。一般人可能會認為, memcpy 是直接做 sequential 的拷貝動作,也就是程式會先把把 i+1 的元素拷貝到 i ,然後才會把 i+2 的元素拷貝到 i+1。很直覺,但是上面這個想法是誰說的?

來讀讀看 manual 吧!

The memcpy() function copies n bytes from memory area src to memory area dest.  The memory areas must not overlap.

換句話說,

If copying takes place between objects that overlap, the behaviour is undefined.

所以程式反應跟你預期中的一樣是運氣好!(不,應該說是運氣差)

要怎麼解決這個問題呢? 第一個,就一個元素一個元素搬囉。第二個,換使用 memmove, memmove 和 memcpy 的差別如下:

The  memmove()  function  copies  n  bytes from memory area src to memory area dest.  The memory areas may overlap: copying takes place as though the bytes in src are first copied into a temporary array that does not overlap src or dest, and the bytes are then copied from the temporary array to dest.

留言

這個網誌中的熱門文章

如何將Linux打造成OpenFlow Switch:Openvswitch

我弟家的新居感恩禮拜分享:善頌善禱

Linux Virtual Interface: TUN/TAP