源代码是这样:procedure Move( const Source; var Dest; count : Integer ); {$IFDEF PUREPASCAL} var S, D: PChar; I: Integer; begin S := PChar(@Source); D := PChar(@Dest); if S = D then Exit; if Cardinal(D) > Cardinal(S) then for I := count-1 downto 0 do D[I] := S[I] else for I := 0 to count-1 do D[I] := S[I]; end; {$ELSE} asm { ->EAX Pointer to source } { EDX Pointer to destination } { ECX Count } PUSH ESI PUSH EDI MOV ESI,EAX MOV EDI,EDX MOV EAX,ECX CMP EDI,ESI JA @@down JE @@exit SAR ECX,2 { copy count DIV 4 dwords } JS @@exit REP MOVSD MOV ECX,EAX AND ECX,03H REP MOVSB { copy count MOD 4 bytes } JMP @@exit@@down: LEA ESI,[ESI+ECX-4] { point ESI to last dword of source } LEA EDI,[EDI+ECX-4] { point EDI to last dword of dest } SAR ECX,2 { copy count DIV 4 dwords } JS @@exit STD REP MOVSD MOV ECX,EAX AND ECX,03H { copy count MOD 4 bytes } ADD ESI,4-1 { point to last byte of rest } ADD EDI,4-1 REP MOVSB CLD @@exit: POP EDI POP ESI end; {$ENDIF} =======================================procedure CopyMemory(Destination: Pointer; Source: Pointer; Length: DWORD); begin Move(Source^, Destination^, Length); end;
41楼贴的是哪个版本的代码?D7以上版本Move过程中的汇编码与你这个是不一样的。
大家仔细看他那个ID :bzworinima ="版猪我日你妈" 。。
D7的汇编码是这样的: asm { ->EAX Pointer to source } { EDX Pointer to destination } { ECX Count } PUSH ESI PUSH EDI MOV ESI,EAX MOV EDI,EDX MOV EAX,ECX CMP EDI,ESI JA @@down JE @@exit SAR ECX,2 { copy count DIV 4 dwords } JS @@exit REP MOVSD MOV ECX,EAX AND ECX,03H REP MOVSB { copy count MOD 4 bytes } JMP @@exit@@down: LEA ESI,[ESI+ECX-4] { point ESI to last dword of source } LEA EDI,[EDI+ECX-4] { point EDI to last dword of dest } SAR ECX,2 { copy count DIV 4 dwords } JS @@exit STD REP MOVSD MOV ECX,EAX AND ECX,03H { copy count MOD 4 bytes } ADD ESI,4-1 { point to last byte of rest } ADD EDI,4-1 REP MOVSB CLD @@exit: POP EDI POP ESI end;
这里应该是
//Dispose(ABuffer); //使用CopyMemory 复制数据,释放数据源指针 $29580D0
Dispose(P); //使用CopyMemory 复制数据,释放数据源指针 $29580D0
CopyMemory的效果相当于“复制”-‘粘贴’
new(P); Move(ABuffer,P, Sizeof(ABuffer)); //可以将数据复制到P, ABuffer 和 P 指向同一个内存区 , ABuffer = $29580D0 ,ip= '192.168.1.132',P = $29580D0这个只是把指针ABuffer的四个字节拷贝到P,而不是拷贝指针指向的内存块,所以持行这个的结果是ABuffer和P都指向一块内存,效果和P:=ABuffer一样。你应该这样调:Move(ABuffer^,P^, Sizeof(TArrayByte));
而用CopyMemory是这样:
CopyMemory(P,ABuffer, Sizeof(TArrayByte));这两个是等效的。注意Move和CopyMemory的参数,两个的参数是不一样的,Move的参数传的是数据块的地址,而CopyMemory传的是指针
procedure CopyMemory(Destination: Pointer; Source: Pointer; Length: DWORD);
begin
Move(Source^, Destination^, Length);
end;
move和CopyMemory的作用是一样的,只不过move的参数被设成const,var,就相当于c++的引用,调用时实际上还是传地址,如果你要用move复制一块内存,就move(pointer1^,pointer2^,length)
而且move也是复制,很多复制的都用move这个词,比如memmove,RtlMoveMemory,mov指令等
Move(ABuffer,P, Sizeof(ABuffer)); //指针传递 Move(ABuffer^,P^, Sizeof(TArrayByte)); //复制内存块CopyMemory(@P, @ABuffer, SizeOf(ABuffer)); //指针传递CopyMemory(P,ABuffer, Sizeof(TArrayByte));//复制内存块
1234+array of byte 四字节的地址,之后跟着一堆 Byte
PArrayByte 其实就是 地址 + TArrayByte
@TArrayByte 表示的就是 这个地址。
Move中的参数 const ABuf 相当于第二行中的 array of byte
CopyMemory中的参数 Pointer 相当于第二行中的 1234
所以 Move PArrayByte 的时候,应该是 p^ 加个小尾巴。
CopyMemory PArrayByte 不用特殊处理。
CopyMemory TArrayByte ,应该加个 @。
说的很对, 在讨论中成长, 共勉, 我提出这个问题,不代表我不懂, 是希望不太熟悉的人看了后,发现自己也在犯同样的错误, 有亲切感, 有错改之, 如果只贴
正确的应用是这样的:
Move(ABuffer,P, Sizeof(ABuffer)); //指针传递
Move(ABuffer^,P^, Sizeof(TArrayByte)); //复制内存块
CopyMemory(@P, @ABuffer, SizeOf(ABuffer)); //指针传递
CopyMemory(P,ABuffer, Sizeof(TArrayByte));//复制内存块
理解有这么深刻吗? delphi论坛发展已经很艰难了,希望大家以后能有个好风气,以良好的心态,不要浮躁, 不要乱扔砖头
谢谢大家关注!
一个人明明是自己错了用不明白,胡说八道了一堆,还不许别人说。你说是这样的人浮躁、傲气,还是说他的人浮躁、傲气?
03年的时候你用 delphi 是一个菜,现在8年过去了,你还是菜得连最基本的语法都搞不清楚。连参数声明代表什么语义都弄不清楚,也好意思说自己在“讨论技术”?不用说,就你这态度,我敢说再过8年你还是一样菜。CSDN 水平差是个不争的事实,原因就是你这种层次的人太多。不懂还到处乱讲也还罢了,别人指出来还说别人人品差。
提高论坛水平一个最有效的办法就是:一旦有乱讲的就大家一起喷,喷到再没人敢自己不懂还瞎指导、不但满嘴跑火车还唧唧歪歪,自然层次就上去了。
发帖交流经验没错,出现错误也很正常,谁都有粗心大意的时候,“大师”也不例外!
我以前也看过很多和LZ类似的错误,人家在别人指出或者自己发现后,总是说“对不起,我自己搞错了,谢谢XXX的提醒(或者应该怎样怎样的)”,而不像LZ非但不去检查自己是否错了?错在哪里?而是百般狡辩什么:“虽然我非常清楚 VCL 的封装”、“在讨论中成长,共勉”、“就是很容易搞错,我才上这个帖子的”、“我搞这个帖子是给不清楚的人看的”看得等等。况且该帖不是什么深奥的技术问题,而是很常见的类型混淆错误,有必要“在讨论中成长,共勉”吗?
自己不虚心,反倒倒打一耙,说别人“浮躁,傲气”、无“大师风范”,真有点是非颠倒!
Move(pSource,pDest,len); //错误
Move(pSource^,pDest^,len); //正确
{$IFDEF PUREPASCAL}
var
S, D: PChar;
I: Integer;
begin
S := PChar(@Source);
D := PChar(@Dest);
if S = D then Exit;
if Cardinal(D) > Cardinal(S) then
for I := count-1 downto 0 do
D[I] := S[I]
else
for I := 0 to count-1 do
D[I] := S[I];
end;
{$ELSE}
asm
{ ->EAX Pointer to source }
{ EDX Pointer to destination }
{ ECX Count } PUSH ESI
PUSH EDI MOV ESI,EAX
MOV EDI,EDX MOV EAX,ECX CMP EDI,ESI
JA @@down
JE @@exit SAR ECX,2 { copy count DIV 4 dwords }
JS @@exit REP MOVSD MOV ECX,EAX
AND ECX,03H
REP MOVSB { copy count MOD 4 bytes }
JMP @@exit@@down:
LEA ESI,[ESI+ECX-4] { point ESI to last dword of source }
LEA EDI,[EDI+ECX-4] { point EDI to last dword of dest } SAR ECX,2 { copy count DIV 4 dwords }
JS @@exit
STD
REP MOVSD MOV ECX,EAX
AND ECX,03H { copy count MOD 4 bytes }
ADD ESI,4-1 { point to last byte of rest }
ADD EDI,4-1
REP MOVSB
CLD
@@exit:
POP EDI
POP ESI
end;
{$ENDIF}
=======================================procedure CopyMemory(Destination: Pointer; Source: Pointer; Length: DWORD);
begin
Move(Source^, Destination^, Length);
end;
asm
{ ->EAX Pointer to source }
{ EDX Pointer to destination }
{ ECX Count } PUSH ESI
PUSH EDI MOV ESI,EAX
MOV EDI,EDX MOV EAX,ECX CMP EDI,ESI
JA @@down
JE @@exit SAR ECX,2 { copy count DIV 4 dwords }
JS @@exit REP MOVSD MOV ECX,EAX
AND ECX,03H
REP MOVSB { copy count MOD 4 bytes }
JMP @@exit@@down:
LEA ESI,[ESI+ECX-4] { point ESI to last dword of source }
LEA EDI,[EDI+ECX-4] { point EDI to last dword of dest } SAR ECX,2 { copy count DIV 4 dwords }
JS @@exit
STD
REP MOVSD MOV ECX,EAX
AND ECX,03H { copy count MOD 4 bytes }
ADD ESI,4-1 { point to last byte of rest }
ADD EDI,4-1
REP MOVSB
CLD
@@exit:
POP EDI
POP ESI
end;
cmp eax, edx
je @@Exit {Source = Dest}
cmp ecx, 32
ja @@LargeMove {Count > 32 or Count < 0}
sub ecx, 8
jg @@SmallMove
@@TinyMove: {0..8 Byte Move}
jmp dword ptr [@@JumpTable+32+ecx*4]
@@SmallMove: {9..32 Byte Move}
fild qword ptr [eax+ecx] {Load Last 8}
fild qword ptr [eax] {Load First 8}
cmp ecx, 8
jle @@Small16
fild qword ptr [eax+8] {Load Second 8}
cmp ecx, 16
jle @@Small24
fild qword ptr [eax+16] {Load Third 8}
fistp qword ptr [edx+16] {Save Third 8}
@@Small24:
fistp qword ptr [edx+8] {Save Second 8}
@@Small16:
fistp qword ptr [edx] {Save First 8}
fistp qword ptr [edx+ecx] {Save Last 8}
@@exit:
ret
nop {4-Byte Align JumpTable}
nop
@@JumpTable: {4-Byte Aligned}
dd @@Exit, @@M01, @@M02, @@M03, @@M04, @@M05, @@M06, @@M07, @@M08
@@LargeForwardMove: {4-Byte Aligned}
push edx
fild qword ptr [eax] {First 8}
lea eax, [eax+ecx-8]
lea ecx, [ecx+edx-8]
fild qword ptr [eax] {Last 8}
push ecx
neg ecx
and edx, -8 {8-Byte Align Writes}
lea ecx, [ecx+edx+8]
pop edx
@FwdLoop:
fild qword ptr [eax+ecx]
fistp qword ptr [edx+ecx]
add ecx, 8
jl @FwdLoop
fistp qword ptr [edx] {Last 8}
pop edx
fistp qword ptr [edx] {First 8}
ret
@@LargeMove:
jng @@LargeDone {Count < 0}
cmp eax, edx
ja @@LargeForwardMove
sub edx, ecx
cmp eax, edx
lea edx, [edx+ecx]
jna @@LargeForwardMove
sub ecx, 8 {Backward Move}
push ecx
fild qword ptr [eax+ecx] {Last 8}
fild qword ptr [eax] {First 8}
add ecx, edx
and ecx, -8 {8-Byte Align Writes}
sub ecx, edx
@BwdLoop:
fild qword ptr [eax+ecx]
fistp qword ptr [edx+ecx]
sub ecx, 8
jg @BwdLoop
pop ecx
fistp qword ptr [edx] {First 8}
fistp qword ptr [edx+ecx] {Last 8}
@@LargeDone:
ret
@@M01:
movzx ecx, [eax]
mov [edx], cl
ret
@@M02:
movzx ecx, word ptr [eax]
mov [edx], cx
ret
@@M03:
mov cx, [eax]
mov al, [eax+2]
mov [edx], cx
mov [edx+2], al
ret
@@M04:
mov ecx, [eax]
mov [edx], ecx
ret
@@M05:
mov ecx, [eax]
mov al, [eax+4]
mov [edx], ecx
mov [edx+4], al
ret
@@M06:
mov ecx, [eax]
mov ax, [eax+4]
mov [edx], ecx
mov [edx+4], ax
ret
@@M07:
mov ecx, [eax]
mov eax, [eax+3]
mov [edx], ecx
mov [edx+3], eax
ret
@@M08:
fild qword ptr [eax]
fistp qword ptr [edx]
end;
另外说一句不是很好听的,我推荐这个帖子是因为大家的回复而不是楼主的言论,我希望楼主能读下大家的回复,自己去system头文件里面看看汇编码,然后再来讨论下这个问题。
procedure CopyMemory(Destination: Pointer; Source: Pointer; Length: DWORD);
begin
Move(Source^, Destination^, Length);
end;
另外说一句,这个procedure CopyMemory在widnows头文件里面,烦请您自己ctrl+鼠标左键点进去自己看看
copymemory只是对move函数的一个封装而已
正如楼上所说,一个是指针一个是地址而已,换个方式本质还是一样的
我记得2007里面才有@@LargeForwardMove这种命名
Delphi在2007以后很多地方都参考了FastCode的设计,应该有这方面的原因
前面有个说“当源和目标对应的内存地址范围有重叠时,Move保证结果是正确的,Copy不能保证。”的,也跟 delphi 毛关系都没有。c89、c99 标准里倒是有(cpp 的标准里应该也有),当内存地址重叠时,标准库里 memcpy 的行为是 undefined,八成是自己在哪看到过但没记清楚是哪个语言的。这里带星星的菜鸟也不止一个两个。别说就1颗的,还有5颗星还照样菜的
我来试着解释一下,有错误请大侠们指正:Move过程的原型为:
procedure Move(const Source; var Dest; count : Integer);
其中的Source和Dest形参是典型的pascal无符号类型,可接收任意类型的实参。如果用C函数改写,可以是:
void Move(const void *Source, void *Dest, int Count);
但是在调用语法上,二者是不相同的。pascal过程传递的是任意类型实参本身,而C函数传递的是指向任意实参的指针。事实上,通过编译器编译后,二者的实参传递方式是完全相同的,即都是以地址方式传递的,只不过pascal过程是靠编译器的“帮忙”来完成的,这和C++函数的引用参数有些类似(只是类似,因C++引用不能使用在无符号类型上)。CopyMemory是一个Windows API函数,其原型是C形式的:
VOID CopyMemory(PVOID Destination, CONST VOID *Source, DWORD Length);
只不过在delphi中这个Windows API函数被替换成了下面这个样子:
procedure CopyMemory(Destination: Pointer; Source: Pointer; Length: DWORD);
begin
Move(Source^, Destination^, Length);
end;
kernel32也没有导出CopyMemory,而是导出RtlMoveMemory,还是个转向导出,实际的代码在ntdll.dll中
Copy & Paste ...