memcpy
function<cstring>
void * memcpy ( void * destination, constvoid * 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.
Theunderlying type of the objects pointed by both the source and destination pointersare irrelevant for this function; The result is abinary 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 notoverlap (for overlapping memory blocks, memmove is a safer approach).
memmove
function<cstring>
void * memmove ( void * destination, constvoid * 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 tooverlap.
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 thecontent is to be copied, type-casted to a pointer of type void*.
source
Pointer to the source of data to becopied, type-casted to a pointer of type void*.
num
Number of bytes to copy.
Return Value
destination is returned.
Example
1 | /* memmove example */ #include <stdio.h> #include <string.h>
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 <string.h>
1 #i nclude <stdio.h>
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 30 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<sizeof(a)/sizeof(int); i++)
{
cout<<a[i]<<"";
}
cout<<endl;
int b[] ={1,2,3,4,5,6,7,8,9,10};
memmove(b, b+4, 6*sizeof(int));
for (int i=0; i<sizeof(b)/sizeof(int); i++)
{
cout<<b[i]<<"";
}
cout<<endl;
int c[] ={1,2,3,4,5,6,7,8,9,10};
memcpy(c+4, c, 6*sizeof(int));
for (int i=0; i<sizeof(c)/sizeof(int); i++)
{
cout<<c[i]<<"";
}
cout<<endl;
int d[] ={1,2,3,4,5,6,7,8,9,10};
memmove(d+4, d, 6*sizeof(int));
for (int i=0; i<sizeof(d)/sizeof(int); i++)
{
cout<<d[i]<<"";
}
cout<<endl;
}
结果为:
memcpy
代码:
;***
;memcpy.asm - contains memcpy and memmove routines
;
; Copyright (c) 1986-1997, MicrosoftCorporation. All right reserved.
;
;Purpose:
; memcpy() copies a source memory buffer toa destination buffer.
; Overlapping buffers are not treatedspecially, so propogation may occur.
; memmove() copies a source memory bufferto a destination buffer.
; Overlapping buffers are treatedspecially, to avoid propogation.
;
;*******************************************************************************
;***
;memcpy - Copy source buffer to destination buffer
;
;Purpose:
; memcpy() copies a source memory buffer toa destination memory buffer.
; This routine does NOT recognizeoverlapping buffers, and thus can lead
; to propogation.
; For cases where propogation must beavoided, 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 destinationbuffer
;
;Purpose:
; memmove() copies a source memory buffer toa destination memory buffer.
; This routine recognize overlappingbuffers to avoid propogation.
; For cases where propogation is not aproblem, 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 tohigher addresses
while (count --)
*dest++ = *source++;
}
else
{
//Overlapping Buffers
//copy from higher addresses to loweraddresses
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++;
case7: *d++ = *s++;
case6: *d++ = *s++;
case5: *d++ = *s++;
case4: *d++ = *s++;
case3: *d++ = *s++;
case2: *d++ = *s++;
case 1: *d++ = *s++;
case0 } //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 FFmov dword ptr [ebp-0E8h],eax
00411BFF 83 BD 18 FF FF FF 07cmp dword ptr [ebp-0E8h],7
00411C06 0F 87 20 01 00 00ja $LN10+33h (411D2Ch)
00411C0C 8B 8D 18 FF FF FFmov ecx,dword ptr [ebp-0E8h]
00411C12 FF 24 8D 38 1D 41 00jmp 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 0100 00 00
mov dword ptr [ebp-0E8h],1
00411D13 EB 0A jmp $LN10+26h (411D1Fh)
00411D15 C7 85 18 FF FF FF 0000 00 00
mov dword ptr [ebp-0E8h],0
00411D1F 83 BD 18 FF FF FF 00cmp dword ptr [ebp-0E8h],0
00411D26 0F 85 ED FE FF FFjne 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();
}