本帖最后由 kshmilyhui 于 2011-07-21 16:21:02 编辑

解决方案 »

  1.   

    什么情况?没看懂,以下是我从坛子里贴来的function ByteArrayToString(ByteArray: array of Byte;  Count: Integer): String;
    begin
      SetLength(Result, Count);
      Move(ByteArray[0], Result[1], Count);
    end;procedure TForm1.FormCreate(Sender: TObject);
    const
      ByteArray: array[0..4] of Byte = ($CE, $D2, $B0, $AE, $31);
    var
      BA : array of Byte;
    begin
      ShowMessage(ByteArrayToString(ByteArray, 5));
      SetLength(BA, 4);
      BA[0] := $CE;
      BA[1] := $D2;
      BA[2] := $B0;
      BA[3] := $AE;
      ShowMessage(ByteArrayToString(BA, 4));
      BA := nil;
    end;
      

  2.   

    http://www.cnblogs.com/del/archive/2008/11/19/1336444.html
    http://www.cnblogs.com/del/archive/2008/11/19/1336467.html
      

  3.   


    function myStrtoHex(s: string): string;
    var tmpstr: string;
      i: integer;
    begin
      tmpstr := '';
      for i := 1 to length(s) do
      begin
        tmpstr := tmpstr + inttoHex(ord(s[i]), 2);
      end;
      result := tmpstr;
    end;function myHextoStr(S: string): string;
    var hexS, tmpstr: string;
      i: integer;
      a: byte;
    begin
      hexS := s;
      if length(hexS) mod 2 = 1 then
      begin
        hexS := hexS + '0';
      end;
      tmpstr := '';
      for i := 1 to (length(hexS) div 2) do
      begin
        a := strtoint('$' + hexS[2 * i - 1] + hexS[2 * i]);
        tmpstr := tmpstr + chr(a);
      end;
      result := tmpstr;
    end;
      

  4.   

    楼上的不对啊    我的意思是 比如说我有一个byte数组 {216,176,202,215}  我在UE中看就是D8 B0 CA D7  把这个数组转成中文就是匕首,同样的把中文转回去 也应该是数组的格式,当然不光能支持中文, 最好是能把数组转成String并且支持中文转换
      

  5.   

    这种声明只要传的 ByteArray 稍微大点儿,进函数就直接挂了。这种到过程/函数结束的时候必挂无疑。
      

  6.   

    function ByteArrayToStr(src:pointer; srclen:dword):pointer;
    asm
      push ecx
      push eax
      push edx
      mov eax,edx
      add eax,9
      call sysgetmem
      mov dword ptr[eax],0
      pop ecx
      mov [eax+4],ecx
      add eax,9
      add eax,ecx
      mov byte ptr[eax],0
      sub eax,ecx
      dec eax
      mov edx,eax
      pop eax
      push edx
      call move
      pop eax
      pop ecx
    end;使用例子:const tmp:array[0..3] of byte=(216,176,202,215);
    var s:string;
    begin
      s:=string(ByteArrayToStr(@tmp,4));
      showmessage(s);
      

  7.   

    另外,注意,使用例子中,如果tmp是动态数组,则必须使用@tmp[0]取址:var s:string;
    tmp:array of byte;
    begin
      setlength(tmp,4);
      tmp[0]:=216;
      tmp[1]:=176;
      tmp[2]:=202;
      tmp[3]:=215;
      s:=string(arraytostr(@tmp[0],4));
      showmessage(s+','+inttostr(length(s)));
    end;
      

  8.   

    我觉得吧,你要是想用汇编的话,好歹先搞清楚一些东西,比如引用字符串计数是0代表什么意义;再比如有没有必要 push/pop ecx;另外,像 mov eax,edx; add eax,9 实际上一条语句就够了,而
      add eax,9
      add eax,ecx
      mov byte ptr[eax],0
      sub eax,ecx
      dec eax
      mov edx,eax
    这一长串只要
      mov byte ptr [eax+ecx+9], 0
      lea edx, [eax+8]
    两句就够了,代码又多,机器码又更长。
    本来全部只要一句 SetString,你折腾了半天结果还有内存泄露
      

  9.   


    对delphi基础知识掌握的不多,对string只知道地址前面有引用计数和长度,没看过计数的函义。push ecx/pop ecx,对delphi来说确实没必要,但这是我的习惯性的东西,我对任何寄存器在使用前都有备份的习惯。至于那一长串,确实没必要这么多代码,本来我也没那么多代码,刚开始没想要加后面那个0的,所以本来不需要将地址移到后面,再移回来,这一长串代码就都省了,所以原本的代码不这样的,后来想起那个0,改的时候也没太意,就加了这些罗嗦的代码。至于内存泄露,使用FastMM4没发现有泄露。
      

  10.   

    以前竟然不知有一个SetString,哎!基础太欠缺,今天又有收获。另外,对string,以前并不知道前面还要有8个字节来记录引用和长度,后来只是看到某人提到一句,前面有引用记数和长度,也没查过函义,只是根据名词,推断,估计当记数为0时,delphi会自动释放。所以我的函数将计数设置为0,应该是正确的。刚才测试了一下,结果也证明我是正确的。
      

  11.   

    System.pasfunction _NewAnsiString(length: Longint): Pointer;
    asm
              TEST    EAX,EAX
              JLE     @@null
              PUSH    EAX
              ADD     EAX,rOff+2                       // one or two nulls (Ansi/Wide)
              AND     EAX, not 1                       // round up to even length
              PUSH    EAX
              CALL    _GetMem
              POP     EDX                              // actual allocated length (>= 2)
              MOV     word ptr [EAX+EDX-2],0           // double null terminator
              ADD     EAX,rOff
              POP     EDX                              // requested string length
              MOV     [EAX-skew].StrRec.length,EDX
              MOV     [EAX-skew].StrRec.refCnt,1
              RET
    @@null:
              XOR     EAX,EAX
    end;看看System._NewAnsiString是怎么建立字符串了内存的关系的你的程序,如果这样运行
    for i:=0 to 1000000 do 
      ByteArrayToStr(@tmp,4);
    结果可想而知如果函数返回值是String,上面的循环就没问题如
    for i:=0 to 1000000 do 
      IntToStr(i);function ByteArrayToStr(src:pointer; srclen:dword):AnsiString;
    但是改成这样显然你的程序不对.
      

  12.   

    先说一下引用计数的问题,昨天没过大脑就直接认为 string(APointer) 的转换不会增加引用计数。刚才仔细考虑了一下,从 string 的模型来看,这个操作应该会增加引用计数的,所以字符串会得到释放。但这里实际上还有另外一个问题,因为昨天认为字符串不会有机会得到释放,这个问题也就不会发生,所以就没提。System.Sys****Mem 系列内存管理函数,是不会经过 System.MemoryManager 的;而 rtl 封装的字符串操作是通过  GetMem/FreeMem 完成的,而这个系列对内存的操作是通过调用 MemoryManager 完成的。换句话说,你前面用 SysGetMem 分配 string 内存会导致,string 的分配与销毁使用的可能不是相同的内存管理器,这个操作可能会引发异常。
    把 SysGetMem 换成 GetMem 就不会引发这个问题。现在的情况说明,你用的是 D2006/D2007 或者使用 FastMM 替换了 rtl 内存管理器的其它更低版本。因为2009及更新版本字符串前增加了4字节内容,你还在用8字节显然版本很老;如果 rtl 还在使用老的 borland 内存管理器版本,由于引用了 fastmm,它们使用的策略不同,所以一旦释放就应该会引发异常。至于现在的情况为什么没出现错误,由于我没研究过 fastmm 的内存分配和释放过程,现在也不打算研究,所以这里也不好说什么。现在也不想开 ide 调,没准打开 FullDebug,fastmm 就会报告这个问题。没出现问题是你的不幸,要是没碰到我,这个错误的知识就会被你当作正确,当你以后碰到由它引发的错误,也不会想到是它的原因。ecx 需不需要保护跟 delphi 就没关系,你习惯如此说明从一开始就不知道哪些是不需要保护的。
      

  13.   


    这我倒真没试过,忘了在哪里看到过个帖子内存申请不要太大,但也没说具体有多大,目前测试过最多的记录是一个200多M的pchar,貌似没问题,以前用byte数组操作一般没超过255,稍微大点是多大?可否赐教
      

  14.   

    更正,那个200M的不是pchar是文件
      

  15.   

    采用pchar分次读入流里,然后生成一个新文件
      

  16.   

    明白了,现将函数改成这样,应该可以了:function ByteArrayToStr(src:pointer; srclen:dword):AnsiString;
    asm
      push ecx
      push eax
      push edx
      push edx
      mov eax,ecx
      call system.@lstrClr
      pop edx
      mov eax,edx
      add eax,10
      and eax,not 1
      push eax
      call system.@getmem
      mov dword ptr[eax],1
      pop edx
      mov word ptr[eax+edx-2],0
      pop ecx
      mov [eax+4],ecx
      lea edx,[eax+8]
      pop eax
      push edx
      call move
      pop eax
      pop ecx
      mov [ecx],eax
    end;
      

  17.   


    delphi内存管理,受教了,谢谢!至于push ecx/pop ecx,我平时的习惯来说,还是需要的,如果是使用pascal调用一个函数肯定是不需要保护的(eax,ecx,edx都不需要)。但我平时习惯在汇编中调用函数,而被调用的函数也是自己用汇编写的,本来正常的情况下,应该是由调用者保存的,但由于平时习惯了,在被调用函数中保存/恢复,这样在调用时就省事了。
      

  18.   


    错误的原因是栈溢出,自然跟栈差不多大就够了procedure foo(x: array of Byte);
    begin
    end.procedure bar;
    var a: array of Byte;
    begin
      SetLength(a, 1024*1024);
      foo(a);
    end;默认情况下栈 1M,这段代码就足够挂掉了
      

  19.   

    另外,之前不清楚新版的delphi中string又加了4个字节(我用的是delphi2007),所以刚才的新版函数也不能用于新版的delphi了,如果要兼容各个版本的delphi,应该改为使用rOff\skew
      

  20.   

    那string转16进制byte数组呢  要求支持中文  有谁能帖下代码 谢谢
      

  21.   

    而且我用的是delphi2010  楼上的很多方法转出来都是空的 
      

  22.   

    delphi2010使用unicode编码,很多字符串函数使用的是字符数不是字节数,LZ可以将string替换为ansistring
      

  23.   

    另外像Move(ByteArray[0], Result[1], Count);中Result[1]这样的语句在2010中已不再支持,唉,没办法
    tbytes bytes:= bytesof(str) ansi编码
      

  24.   

    对了,还有
    str:=stringof(bytes) Tbytes 为ansi编码
      

  25.   

    怎么不支持了?别胡说八道误导人了既然是2010,而且知道 encoding,那就没必要再用 AnsiString 了,直接使用明确编码的 string 类型:
    type GBKString = type AnsiString(936);还是先 SetString,然后再显式转换成 string 就可以了。
      

  26.   

    function myStrtoHex(s: string): string;
    var tmpstr: string;
      i: integer;
    begin
      tmpstr := '';
      for i := 1 to length(s) do
      begin
        tmpstr := tmpstr + inttoHex(ord(s[i]), 2);
      end;
      result := tmpstr;
    end;这段代码在delphi07中转出来就正常,放在2010里转换出来就不对了 悲剧
      

  27.   

    先转成前面我给出的 GBKString 再进行运算
      

  28.   

    个人觉得楼主你那个问题要分2步 
    1 先要找出代表汉子的数字 然后分割成2位十六进制数 
    2 存放在Bytes中