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;
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; 但是改成这样显然你的程序不对.
错误的原因是栈溢出,自然跟栈差不多大就够了procedure foo(x: array of Byte); begin end.procedure bar; var a: array of Byte; begin SetLength(a, 1024*1024); foo(a); end;默认情况下栈 1M,这段代码就足够挂掉了
怎么不支持了?别胡说八道误导人了既然是2010,而且知道 encoding,那就没必要再用 AnsiString 了,直接使用明确编码的 string 类型: type GBKString = type AnsiString(936);还是先 SetString,然后再显式转换成 string 就可以了。
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里转换出来就不对了 悲剧
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;
http://www.cnblogs.com/del/archive/2008/11/19/1336467.html
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;
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);
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;
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,你折腾了半天结果还有内存泄露
对delphi基础知识掌握的不多,对string只知道地址前面有引用计数和长度,没看过计数的函义。push ecx/pop ecx,对delphi来说确实没必要,但这是我的习惯性的东西,我对任何寄存器在使用前都有备份的习惯。至于那一长串,确实没必要这么多代码,本来我也没那么多代码,刚开始没想要加后面那个0的,所以本来不需要将地址移到后面,再移回来,这一长串代码就都省了,所以原本的代码不这样的,后来想起那个0,改的时候也没太意,就加了这些罗嗦的代码。至于内存泄露,使用FastMM4没发现有泄露。
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;
但是改成这样显然你的程序不对.
把 SysGetMem 换成 GetMem 就不会引发这个问题。现在的情况说明,你用的是 D2006/D2007 或者使用 FastMM 替换了 rtl 内存管理器的其它更低版本。因为2009及更新版本字符串前增加了4字节内容,你还在用8字节显然版本很老;如果 rtl 还在使用老的 borland 内存管理器版本,由于引用了 fastmm,它们使用的策略不同,所以一旦释放就应该会引发异常。至于现在的情况为什么没出现错误,由于我没研究过 fastmm 的内存分配和释放过程,现在也不打算研究,所以这里也不好说什么。现在也不想开 ide 调,没准打开 FullDebug,fastmm 就会报告这个问题。没出现问题是你的不幸,要是没碰到我,这个错误的知识就会被你当作正确,当你以后碰到由它引发的错误,也不会想到是它的原因。ecx 需不需要保护跟 delphi 就没关系,你习惯如此说明从一开始就不知道哪些是不需要保护的。
这我倒真没试过,忘了在哪里看到过个帖子内存申请不要太大,但也没说具体有多大,目前测试过最多的记录是一个200多M的pchar,貌似没问题,以前用byte数组操作一般没超过255,稍微大点是多大?可否赐教
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;
delphi内存管理,受教了,谢谢!至于push ecx/pop ecx,我平时的习惯来说,还是需要的,如果是使用pascal调用一个函数肯定是不需要保护的(eax,ecx,edx都不需要)。但我平时习惯在汇编中调用函数,而被调用的函数也是自己用汇编写的,本来正常的情况下,应该是由调用者保存的,但由于平时习惯了,在被调用函数中保存/恢复,这样在调用时就省事了。
错误的原因是栈溢出,自然跟栈差不多大就够了procedure foo(x: array of Byte);
begin
end.procedure bar;
var a: array of Byte;
begin
SetLength(a, 1024*1024);
foo(a);
end;默认情况下栈 1M,这段代码就足够挂掉了
tbytes bytes:= bytesof(str) ansi编码
str:=stringof(bytes) Tbytes 为ansi编码
type GBKString = type AnsiString(936);还是先 SetString,然后再显式转换成 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里转换出来就不对了 悲剧
1 先要找出代表汉子的数字 然后分割成2位十六进制数
2 存放在Bytes中