String

   内存结构:  引用数目|长度|字符串#0

string的前面(8个字节)保存一个StrRec结构
  StrRec = packed record
    refCnt: Longint;  // 引用计数
    length: Longint;  // 长度 
  end;
  
function _LStrLen(const s: AnsiString): Longint;
begin
  Result := 0;
  if Pointer(s) <> nil then
    Result := PStrRec(Integer(s) - sizeof(StrRec)).length;
end;

 

WideString 

  内存结构:  长度|字符串#0#0

 注:长度指定的是字符的个数

 WideString的前四个字节保存字符串的字节数, 没有保存引用计数。

 

function _WStrLen(const S: WideString): Integer;
begin
  if Pointer(S) = nil then
    Result := 0
  else
    Result := PInteger(Integer(S) - 4)^ div sizeof(WideChar);

end; 

 

从上面的结构可以看出,字符串变量S就是指向字符串的第一个字符的指针。(跟C语言相同) 

  Integer(@S[1]) = Interger(S)  ( 第一个字符的下标是1而不是0,与C语言不同 )


  s[0]实际上访问到了字符串负偏移的位置,就是字符串长度(4bytes)的最高byte.(S[0]编译器会提示错误,改成传个变量赋值为0就可以绕过)

 

通过下标访问,可以不受限制访问到字符串的负偏移或者是超过字符串的长度的任意内存,要特别小心。

s := 'test';  

        c := s[-100]; // OK, compile not give you any warning

        c := s[100];  // OK

 

  对于像Move(const Source; var Dest; Count: Integer),Var 类型, 是值,而不是指针,所以不能传str, 而是 str[1]  

 

 

 

 


 

posted on 2011-11-12 12:00  Cabic  阅读(192)  评论(0)    收藏  举报