memcpy memmove 区别

memcpy

function

void * memcpy ( void * destination, const void * source, size_t num );

Copy block of memory

Copies the values of num bytes from the location pointed by source directly to the memory block pointed by destination.
The underlying type of the objects pointed by both the source and destination pointers are irrelevant for this function; The result is a binary copy of the data.

The function does not check for any terminating null character in source - it always copies exactly num bytes.
To avoid overflows, the size of the arrays pointed by both the destination and source parameters, shall be at least num bytes, and should not overlap (for overlapping memory blocks, memmove is a safer approach).

memmove

function

void * memmove ( void * destination, const void * source, size_t num );

Move block of memory

Copies the values of num bytes from the location pointed by source to the memory block pointed by destination. Copying takes place as if an intermediate buffer was used, allowing the destination and source to overlap.
To avoid overflows, the size of the arrays pointed by both the destination and source parameters, shall be at least num bytes.

Parameters

destination

Pointer to the destination array where the content is to be copied, type-casted to a pointer of type void*.

source

Pointer to the source of data to be copied, type-casted to a pointer of type void*.

num

Number of bytes to copy.

Return Value

destination is returned.

Example

1
2
3
4
5
6
7
8
9
10
11

/* memmove example */

#include

#include

int main ()

{

char str[] = "memmove can be very useful......";

memmove (str+20,str+15,11);

puts (str);

return 0;

}

Output:

memmove can be very very useful.

从上面的话可以看出:

memcpy不考虑内存重叠的问题,而memmove考虑内存重叠的问题。

区别:
从DESCRIPTION看来,两者的功能基本相同,唯一不同的是,当 dest 和 src 有重叠的时候选用不同的函数可能会造成不同的结果。不妨写个小程序来测一下:
0 #i nclude
1 #i nclude
2
3 int main()
4 {
5    int i = 0;
6    int a[10];
7
8    for(i; i < 10; i++)
9    {
10        a[i] = i;
11   }
12
13   memcpy(&a[4], a, sizeof(int)*6);
14
15   for(i = 0; i < 10; i++)
16   {
17       printf("%d ",a[i]);
18   }
20
21    printf("/n");
22    return 0;
23 }
很简单的小程序!不过已经足以达到我的目的了:)将上面代码gcc之后再运行,

结果为:0 1 2 3 0 1 2 3 0 1 。
再把第13行改成:memmove(&a[4], a, sizeof(int)*6),重新gcc再运行,

结果为:0 1 2 3 0 1 2 3 4 5 !
呵呵,两者的区别出现了。不过其实这样还不够,继续修改13行: memmove(a, &a[4], sizeof(int)*6) //也就是将源、目的置换一下而已
重新gcc编译再运行,结果为:4 5 6 7 8 9 6 7 8 9 。
还不够,继续修改13行为: memcpy(a, &a[4], sizeof(int)*6); gcc并运行,结果仍为: 4 5 6 7 8 9 6 7 8 9 !
至此真相已经大白了。对比上面四个结果,不难得出以下结论:
1. 当 src 和 dest 所指内存区有重叠时,memmove 相对 memcpy 能提供保证:保证能将 src 所指内存区的前 n 个字节正确的拷贝到 dest 所指内存中;
2. 当 src 地址比 dest 地址低时,两者结果一样。换句话说,memmove 与 memcpy 的区别仅仅体现在 dest 的头部和 src 的尾部有重叠的情况下;

上面的例子是别人的:

但是我用下面的实验测试,发现memcpy与memmove的结果多是一样的,我使用了VC6.0,VS2005,DevC++(gcc 3.4.5)

void TestMemcpy()

{

int a[] = {1,2,3,4,5,6,7,8,9,10};

memcpy(a, a+4, 6*sizeof(int));

for (int i=0; i

{

cout< <<" ";

}

cout<

int b[] = {1,2,3,4,5,6,7,8,9,10};

memmove(b, b+4, 6*sizeof(int));

for (int i=0; i

{

cout< <<" ";

}

cout<

int c[] = {1,2,3,4,5,6,7,8,9,10};

memcpy(c+4, c, 6*sizeof(int));

for (int i=0; i

{

cout< <<" ";

}

cout<

int d[] = {1,2,3,4,5,6,7,8,9,10};

memmove(d+4, d, 6*sizeof(int));

for (int i=0; i

{

cout< <<" ";

}

cout<

}

结果为:

clip_image001

memcpy

代码:
;***
;memcpy.asm - contains memcpy and memmove routines
;
;       Copyright (c) 1986-1997, Microsoft Corporation. All right reserved.
;
;Purpose:
;       memcpy() copies a source memory buffer to a destination buffer.
;       Overlapping buffers are not treated specially, so propogation may occur.
;       memmove() copies a source memory buffer to a destination buffer.
;       Overlapping buffers are treated specially, to avoid propogation.
;
;*******************************************************************************
;***
;memcpy - Copy source buffer to destination buffer
;
;Purpose:
;       memcpy() copies a source memory buffer to a destination memory buffer.
;       This routine does NOT recognize overlapping buffers, and thus can lead
;       to propogation.
;       For cases where propogation must be avoided, memmove() must be used.
;
;       Algorithm:

       void* memcpy(void* dest, void* source, size_t count)

      {

           void* ret = dest;

          //copy from lower address to higher address

          while (count--)

                  *dest++ = *source;

           return ret;

      }

memmove

memmove - Copy source buffer to destination buffer
;
;Purpose:
;       memmove() copies a source memory buffer to a destination memory buffer.
;       This routine recognize overlapping buffers to avoid propogation.
;       For cases where propogation is not a problem, memcpy() can be used.
;
;   Algorithm:

    void* memmove(void* dest, void* source, size_t count)

   {

       void* ret = dest;

      if (dest <= source || dest >= (source + count))

       {

          //Non-Overlapping Buffers
         //copy from lower addresses to higher addresses

         while (count --)

               *dest++ = *source++;

     }

     else

     {

        //Overlapping Buffers
       //copy from higher addresses to lower addresses

       dest += count - 1;

       source += count - 1;

       while (count--)

                *dest-- = *source--;l

     }

      return ret;

   }

另一种实现:

void* mymemcpy( void* dest, const void* src, size_t count )
{
     char* d = (char*)dest;
     const char* s = (const char*)src;
   //   int n = (count + 7) / 8; // count > 0 assumed
     int n = count >> 3;
     switch( count & 7 )
     {
               do {   *d++ = *s++;
     case 7:         *d++ = *s++;
     case 6:         *d++ = *s++;
     case 5:         *d++ = *s++;
     case 4:         *d++ = *s++;
     case 3:         *d++ = *s++;
     case 2:         *d++ = *s++;
     case 1:         *d++ = *s++;
     case 0           } //while (--n > 0);
                  while (n-- > 0)
     }

     return dest;
}

上面的switch与while的交错使用,还是比较独特的。

注意下面这个函数的独特的汇编实现:

218: switch( count & 7 )

00411BF3 8B 45 10 mov eax,dword ptr [count]

00411BF6 83 E0 07 and eax,7

00411BF9 89 85 18 FF FF FF mov dword ptr [ebp-0E8h],eax

00411BFF 83 BD 18 FF FF FF 07 cmp dword ptr [ebp-0E8h],7

00411C06 0F 87 20 01 00 00 ja $LN10+33h (411D2Ch)

00411C0C 8B 8D 18 FF FF FF mov ecx,dword ptr [ebp-0E8h]

00411C12 FF 24 8D 38 1D 41 00 jmp dword ptr (411D38h)[ecx*4]

219: {

220: do {

221: *d++ = *s++;

00411C19 8B 45 F8 mov eax,dword ptr [d]

00411C1C 8B 4D EC mov ecx,dword ptr [s]

00411C1F 8A 11 mov dl,byte ptr [ecx]

00411C21 88 10 mov byte ptr [eax],dl

00411C23 8B 45 F8 mov eax,dword ptr [d]

00411C26 83 C0 01 add eax,1

00411C29 89 45 F8 mov dword ptr [d],eax

00411C2C 8B 4D EC mov ecx,dword ptr [s]

00411C2F 83 C1 01 add ecx,1

00411C32 89 4D EC mov dword ptr [s],ecx

222: case 7: *d++ = *s++;

case 6, 5….1 都是与上面一样的汇编代码

229: case 0: ;

230: }// while (--n > 0);

231: while (n-- > 0);

00411CF9 8B 45 E0  mov eax,dword ptr [n]

00411CFC 8B 4D E0  mov ecx,dword ptr [n]

00411CFF 83 E9 01  sub ecx,1

00411D02 89 4D E0  mov dword ptr [n],ecx

00411D05 85 C0 test eax,eax

00411D07 7E 0C   jle $LN10+1Ch (411D15h)

00411D09 C7 85 18 FF FF FF 01 00 00 00

mov dword ptr [ebp-0E8h],1

00411D13 EB 0A jmp $LN10+26h (411D1Fh)

00411D15 C7 85 18 FF FF FF 00 00 00 00  mov dword ptr [ebp-0E8h],0

00411D1F 83 BD 18 FF FF FF 00 cmp dword ptr [ebp-0E8h],0

00411D26 0F 85 ED FE FF FF jne mymemcpy+59h (411C19h)

232: }

233:

234: return dest;

00411D2C 8B 45 08 mov eax,dword ptr [dest]

235: }

00411D2F 5F pop edi

00411D30 5E pop esi

00411D31 5B pop ebx

00411D32 8B E5 mov esp,ebp

00411D34 5D pop ebp

00411D35 C3 ret

00411D36 8B FF mov edi,edi

注意不要产生思维定势了:比如下面的代码是一个很正常的代码,结果我因为分析上面的代码产生了思维定势,还一直好奇以为很难的代码呢:

//注意不要产生思维定势了。

void TestWhile()

{

//int i;

char i;

do

{

scanf("%c",&i);

switch(i)

{

case '1':

printf("1");

break; //注意,这是跳出switch

default:

printf("error");

break;

}

}while(i != '1');

getch();

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值