memcpy memcopy 的实现
2019-07-13 15:50 发布
生成海报
先是VC中的实现直接字符:
void * __cdecl memcpy ( void * dst , const void * src , size_t count ) {
void * ret = dst ;
/*
* copy from lower
addresses to higher addresses
*/
while ( count --) {
*( char *) dst = *( char *) src ;
dst = ( char *) dst + 1 ; //不能对void* 直接加1,因为unknown size
src = ( char *) src + 1 ;
}
return ( ret ); }
void * __cdecl memmove ( void * dst , const void * src , size_t count ) {
void * ret = dst ;
if ( dst <= src || ( char *) dst >= (( char *) src + count )) {
/*
*
Non-Overlapping Buffers
*
copy from lower addresses to higher addresses
*/
while ( count --) {
*( char *) dst = *( char *) src ;
dst = ( char *) dst + 1 ;
src = ( char *) src + 1 ;
}
}
else {
/*
*
Overlapping Buffers
*
copy from higher addresses to lower addresses
*/
dst = ( char *) dst + count - 1 ;
src = ( char *) src + count - 1 ;
while ( count --) {
*( char *) dst = *( char *) src ;
dst = ( char *) dst - 1 ;
src = ( char *) src - 1 ;
}
}
return ( ret ); }
引用别人的:
Intel 80386 以上支持的指令集中MOVSD 指令和REP 指令配合将DWORD (32bit )在内存间移动,即在一个时钟周期copy 四个字节,整整比MOVSB (8bit )指令快了四倍。但是使用MOVSD 移动到的目的内存地址必须是32bit 对齐的(DWORD-aligned )。简单说明从低位到高位的内存copy 如下。
设L 为要拷贝的总字节数,Dest 为目的起始地址,X 为从Dest 开始没有DWORD-aligned 的字节数,Y 为要拷贝的DWORD 个数,Z 为剩余的没有DWORD-aligned 字节数。那么有公式如下:
X = (4 – Dest & 3 ) & 3
(bytes) // 低两位为0 的地址是DWORD-aligned
Y = (L – X) >> 2
(DWORDs) // 整除以4 是DWORD 个数
Z = (L – X – Y * 4) (bytes)
总结一下,对大段的内存移动,用memmove 将是非常优化的,相反若用c 写的code 会降低四倍效率,这就是为什么要用ASM 直接实现的原因。
下面是ASM版本的实现:
memcpy: /*-----------------------------------------------------------------------* * filename -
memcpy.cas * * function(s) *
memcpy - copy a block
of n bytes from src to dst
*-----------------------------------------------------------------------*/ #pragma inline #include #include #undef memcpy
/* not an intrinsic */ /*-----------------------------------------------------------------------* Name
memcpy - copy
a block of n bytes from src
to dst Usage
void *memcpy(void *dst,
const void *src, size_t n); Prototype in
mem.h & string.h Description
memcpy copies a block of n
bytes from src to dst.
No
overlap checking is performed. Return value
memcpy returns dst *------------------------------------------------------------------------*/ #if defined(__FARFUNCS__) #include <_farfunc.h> #endif #if 1
/* No overlap
checking version */ void * _FARFUNC memcpy(void
*dst, const void *src, size_t n) { #if !(LDATA)
_ES = _DS; #endif #if
defined(__LARGE__) || defined(__COMPACT__) asm mov
dx,ds
/* save ds */ #endif asm LES_
di, dst asm LDS_
si, src asm mov
cx,n asm shr
cx,1 asm cld asm rep
movsw asm jnc
cpy_end asm movsb cpy_end: #if
defined(__LARGE__) || defined(__COMPACT__)
asm mov
ds,dx
/* restore */ #endif
return(dst); } #else
/* Overlap checking
version */ void * _FARFUNC memcpy(void
*dst, const void *src, size_t n) {
movmem(src,dst,n);
return(dst); } #endif memmove: /*-----------------------------------------------------------------------* * filename -
movmem.cas * * function(s) *
movmem - move a block
of bytes *
memmove - move a block
of bytes
*-----------------------------------------------------------------------*/ #pragma inline #include #include /*-----------------------------------------------------------------------* Name
movmem - move
a block of bytes Usage
void movmem(void *src,
void *dst, unsigned len); Prototype in
mem.h Description
movmem copies a block of len
bytes from src to dst. If the
source
and destination arrays overlap, the
copy direction
is
chosen so that the data is always
copied correctly. Return value
There is no return value *------------------------------------------------------------------------*/ #if defined(__FARFUNCS__) #include <_farfunc.h> #endif void _FARFUNC movmem(const
void *src, void *dst, unsigned len) { #if LDATA #if
!defined(__HUGE__)
asm push
ds #endif
if (((void huge
*)src) < ((void huge *)dst)) #else
_ES = _DS;
if (src < dst) #endif
{ /* travel
backward, need to adjust ptrs later
*/
asm
std
asm
mov ax,
1
}
else
{ /* travel
forward, no need to adjust ptrs
*/
asm
cld
asm
xor ax,
ax
} asm LDS_
si, src asm LES_
di, dst asm mov
cx, len asm or
ax, ax asm jz
movit asm add
si, cx /*
backward move, adjust ptrs to end-1
*/ asm dec
si asm add
di, cx asm dec
di movit: asm test
di, 1 asm jz
isAligned asm jcxz
done asm movsb asm dec
cx isAligned: asm sub
si, ax /*
compensate for word moves */ asm sub
di, ax asm shr
cx, 1 asm rep
movsw asm jnc
noOdd asm add
si, ax /*
compensate for final byte */ asm add
di, ax asm movsb noOdd: done: asm cld #if
defined(__LARGE__) || defined(__COMPACT__)
asm pop
ds #endif } /*-----------------------------------------------------------------------* Name
memmove - move
a block of bytes Usage
void memmove(void *dst,
const void *scr, unsigned len); Prototype in
mem.h Description
memmove copies a block of len
bytes from src to dst. If
the
source
and destination arrays overlap, the
copy direction
is
chosen so that the data is always
copied correctly. Return value
dst *------------------------------------------------------------------------*/ void *_CType _FARFUNC
memmove( void *dst, const void *src,
size_t n ) { movmem( (void
*)src, dst, n ); return( dst
); }
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮