CnPack Tip#1 如何理解Move
Thx: 小峰
http://www.cnpack.org
CnPack IV QQ Group: 130970
2007-01-31
Q:
procedure Move(const Source; var Dest; Count: Integer);
问一下这里的参数Source和Dest没有说明数据类型,那具体应该如何使用啊?
var
xx, yy: array [0..6] of Char;
begin
FillChar(xx, 7, #0);
xx := 'abcdef';
Move(xx, yy, 4);
Move(xx[0], yy[0], 4)
//上面这两条语句有什么区别
end;
A:
xx, yy就是一块数据。
xx[0] 就是这块数据的第一个字符
这两个的起始地址相同,因此move的结果也相同了。
测试代码:
procedure TForm1.btnXClick(Sender: TObject);
var
xx, yy: array [0..6] of Char; // 内容存在栈里
a: array of Char; // 内容存在堆里,这就可以理解为什么动态数组a代表的是字符串的指针了
begin
SetLength(a, 10);
FillChar(xx, 7, #0);
xx := 'abcdef';
a[0]:='A';
a[1]:='B';
Move(xx, yy, 4);
Move(xx[0], yy[0], 4);
Move(xx,a[0],4);
end;
注释一下Move
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 //精华1:小心,别覆盖了Source
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 //精华2: 放之四海皆准。
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}
注:
Passion:
C/Pascal等高级语言里头的指针其实是一个存储了地址的内存单元,
其存储的内容(是一个地址)所指的地方才是这个指针所指的内容。
而I:Integer只是一个内存单元,I的内容是整型变量,没有地址的说法。
@I才能得到I的地址。
[
本帖最后由 skyjacker 于 2007-1-31 15:50 编辑 ]