AnsiString?PChar?赋值?转换?

  AnsiString,Delphi开发人员指南这么解释的,AnsiString就是指向堆中字符串结构的指针,显示了AnsiString的分配情况。  
  帮助上这么解释:长字符串保存有成员数量,PChar没有,长字符串(相对于ShortString类型来说,这里就是AnsiString)是Null结尾的,并且包含了引用记数,PChar就是一个简单的Null结尾的字符串。AnsiString之间的赋值是赋值数据,而PChar赋值是改变指针的指向。  
   
  同样存储LIKE,两种类型差异:  
   
  string简图:  
  --------------------------------------------------------  
  |   引用计数位   |   长度位   |     L   |   I   |   K   |   E   |   #0     |  
  --------------------------------------------------------  
   
  PChar简图:  
  -------------------------  
  |     L   |   I   |   K   |   E   |   #0     |  
  -------------------------  
   
  而string的指针通常指向数据位第一个,访问前面的引用计数和长度位的时候word   ptr   [eax-$04],   dword   ptr   [eax-$08],这一类的代码。  
   
  它们之间的转换,Delphi开发人员指南里面是这么写的:不需要用StrPas和StrPCopy去来回转换string和PChar类型。我们在前面讲过,可以把AnsiString强制转化成PChar。在想把PChar转换成AnsiString时,可以直接赋值:StringVar   :=   PCharVar;    
   
  StrPas的原型是什么?我悄悄地告诉你啊,不要告诉别人哦!:〉  
  function   StrPas(const   Str:   PChar):   string;  
  begin  
      Result   :=   Str;  
  end;  
  哈哈,搞笑吧。Borland弄了这么一个东西……   -_-bb  
  其实是为了兼容而设立的。  
   
  StrPCopy相对来讲就比较复杂了,是把string强制转化成PChar之后按照string的长度进行PChar之间复制。  
   
  function   StrPCopy(Dest:   PChar;   const   Source:   string):   PChar;  
  begin  
      Result   :=   StrLCopy(Dest,   PChar(Source),   Length(Source));  
  end;  
   
  而StrLCopy类似于C语言里面的strcpy这种用来复制内容的函数,所以尽量用StrLCopy来给PChar赋值,  
  因为会保护现场,用赋值号,就改变了指针的指向了。  
   
  有关Delphi开发人员指南里面的介绍,我写了这么一些代码来验证一下:  
  var  
      P:   PChar;  
      S:   string;  
  begin  
      S   :=   '1234567ABCDE';  
      P   :=   PChar(S);      
      S   :=   P;  
      ShowMessage(S);  
      ShowMessage(P);  
      ShowMessage(IntToStr(SizeOf(S)));  
  end;  
   
  当执行到S   :=   '1234567ABCDE';时,汇编代码如下:  
   
  第一句:S   :=   '1234567ABCDE';  
  0045B130   8D45FC                       lea   eax,[ebp-$04]  
  0045B133   BAB0B14500               mov   edx,$0045b1b0  
  0045B140   E8E791FAFF               call   @LStrLAsg  
   
  LStrLAsg就是字符串赋值地内建函数。正验证了帮助里面的那句string之间是数据Copy。  
   
  第二句:P   :=   PChar(S);  
  0045B13D   8B45FC                       mov   eax,[ebp-$04]  
  0045B140   E8FF95FAFF               call   @LStrToPChar  
  0045B145   8BD8                           mov   ebx,eax  
   
  进入这一句了,LStrToPChar是不是很容易理解呢,string转化为PChar。然后简单的赋地址,指针改变指向。  
   
  好了该由PChar转换到string了,这个是一个重点。  
   
  第三句:S   :=   P;  
  0045B147   8D45FC                       lea   eax,[ebp-$04]  
  0045B14A   8BD3                           mov   edx,ebx  
  0045B14C   E83393FAFF               call   @LStrFromPChar  
   
  LStrFromPChar是由PChar转换string的一个内建函数。  
   
  进入LStrFromPChar的代码  
  @LStrFromPChar  
  00404484   31C9                           xor   ecx,ecx  
  00404486   85D2                           test   edx,edx  
  00404488   7421                           jz   +$21  
  0040448A   52                               push   edx  
  0040448B   3A0A                           cmp   cl,[edx]  
  0040448D   7417                           jz   +$17  
  0040448F   3A4A01                       cmp   cl,[edx+$01]  
  00404492   7411                           jz   +$11  
  00404494   3A4A02                       cmp   cl,[edx+$02]  
  00404497   740B                           jz   +$0b  
  00404499   3A4A03                       cmp   cl,[edx+$03]  
  0040449C   7405                           jz   +$05  
  0040449E   83C204                       add   edx,$04  
  004044A1   EBE8                           jmp   -$18           //循环得到字符串长度。  
  004044A3   42                               inc   edx  
  004044A4   42                               inc   edx  
  004044A5   42                               inc   edx  
  004044A6   89D1                           mov   ecx,edx  
  004044A8   5A                               pop   edx  
  004044A9   29D1                           sub   ecx,edx   //到这里得到了PChar的长度。  
  004044AB   E9D4FEFFFF               jmp   @LStrFromPCharLen  
  004044B0   C3                               ret    
   
  然后处理成string的长度的转化:  
   
  @LStrFromPCharLen  
  00404384   53                               push   ebx  
  00404385   56                               push   esi  
  00404386   57                               push   edi  
  00404387   89C3                           mov   ebx,eax  
  00404389   89D6                           mov   esi,edx  
  0040438B   89CF                           mov   edi,ecx  
  0040438D   89F8                           mov   eax,edi  
  0040438F   E8C4FFFFFF               call   @NewAnsiString  
   
  这里调用了NewAnsiString来生成一个新的标准字符串。  
  我们跳过来顺道看看string到底怎么生成的。string生成尽管是自动的,  
  其实和手工声称PChar差不多,不同的是比PChar多的长度位和引用计数的初始化。  
   
  @NewAnsiString  
  00404358   85C0                           test   eax,eax  
  0040435A   7E24                           jle   +$24  
  0040435C   50                               push   eax  
  0040435D   83C00A                       add   eax,$0a  
  00404360   83E0FE                       and   eax,-$02  
  00404363   50                               push   eax  
  00404364   E8B3E3FFFF               call   @GetMem     //得到字符串长度后申请内存。  
  00404369   5A                               pop   edx  
  0040436A   66C74402FE0000       mov   word   ptr   [edx+eax-$02],$0000  
  00404371   83C008                       add   eax,$08      
  00404374   5A                               pop   edx  
  00404375   8950FC                       mov   [eax-$04],edx               //这里应该就长度位  
  00404378   C740F801000000       mov   [eax-$08],$00000001   //这里是引用记数位  
  0040437F   C3                               ret    
  00404380   31C0                           xor   eax,eax  
  00404382   C3                               ret    
  00404383   90                               nop    
   
  继续LStrFromPCharLen下面的代码。  
  00404394   89F9                           mov   ecx,edi  
  00404396   89C7                           mov   edi,eax  
  00404398   85F6                           test   esi,esi  
  0040439A   7409                           jz   +$09  
  0040439C   89C2                           mov   edx,eax  
  0040439E   89F0                           mov   eax,esi  
  004043A0   E873E5FFFF               call   Move             //然后把这个新的字符串的数据移到需要的字符串。  
  004043A5   89D8                           mov   eax,ebx  
  004043A7   E8E8FEFFFF               call   @LStrClr     //清理NewAnsiString生成的临时字符串  
  004043AC   893B                           mov   [ebx],edi  
  004043AE   5F                               pop   edi  
  004043AF   5E                               pop   esi  
  004043B0   5B                               pop   ebx  
  004043B1   C3                               ret    
   
  ShowMessage直接输入string就是直接调用。  
  ShowMessage(S);  
  0045B159   8B45FC                       mov   eax,[ebp-$04]  
  0045B15C   E8638EFDFF               call   ShowMessage  
   
  而输入PChar,嗬嗬,又调用了上面说到的LStrFromPChar然后才是调用ShowMessage,  
  其他的也是如此,如果输入参数没有转换,而是输入了PChar,那编译器会这么处理。  
  ShowMessage(P);  
  0045B161   8D45F8                       lea   eax,[ebp-$08]  
  0045B164   8BD3                           mov   edx,ebx  
  0045B166   E81993FAFF               call   @LStrFromPChar  
  0045B16B   8B45F8                       mov   eax,[ebp-$08]  
  0045B16E   E8518EFDFF               call   ShowMessage  
   
  最后一句:ShowMessage(IntToStr(SizeOf(S)));  
  如果没有差错的话,就是4,一个指针的长度。  
   
  好了,一切都清晰了。  
  S   :=   S;    
  使用了LStrLAsg内建函数来赋值。  
   
  P   :=   P;  
  地址赋值。  
   
  P   :=   PChar(S);  
  调用LStrToPChar转换为PChar之后地址赋值。  
   
  S   :=   P;  
   
  这个最最麻烦,  
  调用LStrFromPChar来转化。  
  代码中首先取得PChar的长度,  
  然后调用LStrFromPCharLen用string的长度赋值,  
  代码中首先使用NewAnsiString在堆中生成一个临时字符串,  
  其次调用Move,Copy到目的字符串,  
  最后清理临时字符串。  
   
  好了,我又一次胡诌完毕了。请大家执正!

 

转载自:http://topic.csdn.net/t/20040220/18/2758117.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值