变量s的内存结构为(一共12个辅助字节,以前是8个字节) (字符串编码)A8 03 (字符宽度)01 00 (引用计数)FF FF FF FF (字符串长度)0A 00 00 00 (实际内容)31 32 33 34 35 36 37 38 39 30 (结束符)00
01~02 字节是代码页,如上面的0x03A8为十进制的936,表示简体中文GBK 03~04 字节表示每个字符所占的字节数(ANSI为1,Unicode为2) 05~08 字节是该字符串的引用计数 09~12 字节是该字符串的字符个数 13~?? 字节就是字符串实际的内容了 ?? 最后一个字节是00,字符串的结束符
对于string变量类型s,它实际上是一个指针,指向字符串首个字符的地址,也就是第13个字节
这里需要注意的是,在Delphi 2009以前的版本中是没有描述代码页的4字节的(代码页+字符宽度),而是直接从第05字节开始(引用计数)。
上面的字符串引用计数为什么会是0xFFFFFFFF呢?因为该字符串是常量,对于常量字符串,引用计数总是-1 若有N处相同的字符串常量时,就有N份的拷贝,这样就造成了空间上的浪费,Delphi并未作出优化 下面的代码就可以说明问题,两次显示的字符串内存地址不同。
- procedure Foo();
- var
- s: AnsiString;
- begin
- s := '1234567890';
- ShowMessage(IntToHex(Integer(@s[1]), 8));
- end;
-
- procedure TForm1.Button1Click(Sender: TObject);
- var
- s: AnsiString;
- begin
- s := '1234567890';
- ShowMessage(IntToHex(Integer(@s[1]), 8));
- Foo;
- end;
接着看看下面的代码
- var
- s: AnsiString;
- begin
- s := Caption;
- ShowMessage(IntToHex(Integer(@s[1]), 8));
- end;
由于没有使用常量字符串,所以引用计数不再是-1 (代码页)A8 03 (字符宽度)01 00 (引用计数是1)01 00 00 00 (字符串长度)05 00 00 00 (字符内容)46 6F 72 6D 31 (结束符)00
在知道了string的内存结构后,我们就可以通过代码来观测引用计数的值了
- var
- s, s2: AnsiString;
- p: ^Integer;
- begin
- s := Caption;
- p := Pointer(@s[1]); // 应该是得到s[1]的地址,即第一个字符的地址
- Dec(p, 2); // 前移2个单位(8个字节,因为每个^integer类型的数据长度是4)
- ShowMessage(IntToStr(p^));
-
- s2 := s;
- ShowMessage(IntToStr(p^));
- end;
http://blog.csdn.net/aqtata/article/details/38905387
|
请发表评论