如何理解Move参数中的const Source和var Dest

    技术2022-05-11  71

    如何理解Move参数中的const Source和var Dest

    总结作者:SkyJacker贡献者:小峰,LiuXiaohttp://www.cnpack.orgCnPack IV  QQ Group: 1309702007-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 的 Pascal 源码(Windows XP Sp2 Delphi6 + Update2 ):

    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     ESIend;{$ENDIF}

    注:

    C/Pascal等高级语言里头的指针其实是一个存储了地址的内存单元,其存储的内容(是一个地址)所指的地方才是这个指针所指的内容。而I:Integer只是一个内存单元,I的内容是整型变量,@I才能得到I的地址。

    Pascal中的无类型变量,相当于C中的void。参数const Source; var Dest; 可以理解为两块内存区域。这两参数调用时在汇编中的实现,便是将Source和Dest的“地址值”作为参数传入,而并非传入这两变量本身。

    但在函数内部的Pascal实现中,Source是传入的地址再指了一次而得到的结果,因此仍然代表传进来之前的Source。欲取得汇编中实现时传入来的地址,则需要用@Source。也就是说,这个var封装并且隐藏了函数被调用时传入的取地址操作和函数体内部使用时指了一次的操作。

     

    最新回复(0)