Delphi - 字符串 详解
来自:http://www.cnblogs.com/huangjacky/archive/2009/12/10/1620950.html
------------------------------------------------------------------------------------------
技术交流,DH解说.
以前写过一次,现在全部重写吧.比较基础了,高手莫笑.
记得有次在盒子上面看到有个人出的面试题,第一题就是:
AnsiString 和 WideString的区别.
好这里先留给大家想想,我讲完了,大家就应该知道了.嘿嘿.
首先分类:
1 ShortString,可以容纳255个字符,主要为了老版本兼容
2 AnsiString,可以容纳2的31次方个字符,D2009前默认的String类型
3 UnicodeString,可以容纳2的30次方个字符,D2009及以后的默认String类型
4 WideString,可以容纳2的30次方个字符,主要在COM中用的比较多.
好一个一个来讲:
ShortString
我们看到上面说的它可以容纳255个字符,但是它所占的空间是字符长度加1,为什么?
我们来看个例子:
1
2
3
4
5
6
7
8
|
Procedure TForm3 . Btn1Click(Sender: TObject); Var S: String [ 15 ]; Begin S:= 'HuangJackyAAAAA' ; ShowMessageFmt( '%d' , [Length(S)]); //15个字符 ShowMessageFmt( '%d' , [SizeOf(S)]); //空间大小是16 End ; |
从上面的代码我们可以看出来,ShortString变量不是用的指针,而是直接就是内存块,不然SizeOf应该是4的.既然我们发现这个问题,我们肯定要去看下它的内存情况吧.
我们可以发现它第一个字节用来存放的字符串的长度,所以它只能容纳255个字符,$FF,是吧.
那么把上面的代码改一下:
1
2
3
4
5
6
7
8
|
Procedure TForm3 . Btn1Click(Sender: TObject); Var S: String [ 15 ]; Begin S:= 'HuangJackyAAAAA' ; ShowMessageFmt( '%d' , [ord(S[ 0 ])]); //同样是15,哈哈. ShowMessageFmt( '%d' , [SizeOf(S)]); End ; |
好的,这样我们已经掌握了第一种字符串了.
AnsiString
用同样的代码测试:
1
2
3
4
5
6
7
8
|
Procedure TForm3 . Btn1Click(Sender: TObject); Var S: AnsiString ; Begin S:= 'HuangJackyAAAAA' ; ShowMessageFmt( '%d' , [Length(S)]); //15 ShowMessageFmt( '%d' , [SizeOf(S)]); //4 End ; |
说明变量S只是一个指针.
好去看看这个地址:
是吧,那么存放实际字符串这块内存是怎么样组织的呢?
偏移 | -12 | -10 | -8 | -4 | 0-长度-1 | 最后一位 |
内容 | 字符页码 | 每个字符大小 | 引用次数 | 字符串长度 | 实际内容 | 0 |
名词解释下:页码是什么?编码,UTF-8或者GBK这些.
我们知道字符串其实是一个对象,但是它的释放却不需要我们操心,那就是因为当引用次数为0的时候,编译器会自动释放.
我们上面说了AnsiString能容纳2的31次方个字符,是的,因为它的长度占了4个字节.
好我们写代码来测试一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
Procedure TForm3 . Btn1Click(Sender: TObject); Var S: AnsiString ; I: Integer ; Begin S:= 'HuangJackyAAAAA' ; I:= Integer (S); ShowMessage(IntToHex(PWord(I- 12 )^, 4 )); //$03A8 ShowMessage(IntToHex(PWord(I- 10 )^, 4 )); //$0001,AnsiString中一个元素就一个字节 ShowMessage(IntToHex(PCardinal(I- 8 )^, 8 )); //$FFFFFFFF ShowMessage(IntToHex(PCardinal(I- 4 )^, 8 )); //$0000000F ShowMessageFmt( '%d' , [Length(S)]); //15 ShowMessageFmt( '%d' , [SizeOf(S)]); //4 End ; |
来贴图一张:
和我们上面说的一样吧.
我们再去看下页码对应的是什么编码.$03A8就是936,查MSDN 936 - gb2312.哈哈.
UnicodeString的内存分布也是一样的.所以我感觉-12和-10加入主要为了UnicodeString服务的.因为Unicode里面的编码就很多了,每个元素的大小也根据编码不同有所不同的.
进入WideString之前,我们看看Delphi里面Length函数是怎么实现的.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
Unit3 . pas .40 : I:=Length(S); 004B33CD 8B45FC mov eax,[ebp- $04 ] 004B33D0 85C0 test eax,eax 004B33D2 7418 jz $004b33ec 004B33D4 8BD0 mov edx,eax 004B33D6 83EA0A sub edx, $0a 004B33D9 66833A01 cmp word ptr [edx], $01 004B33DD 740D jz $004b33ec 004B33DF 8D45FC lea eax,[ebp- $04 ] 004B33E2 33C9 xor ecx,ecx 004B33E4 8B55FC mov edx,[ebp- $04 ] 004B33E7 E8782EF5FF call @InternalLStrFromUStr //因为我们不是用的Unicode所以这里会被跳过 004B33EC 85C0 test eax,eax 004B33EE 7405 jz $004b33f5 004B33F0 83E804 sub eax, $04 //对就是这样,偏移-4 004B33F3 8B00 mov eax,[eax] //取得它的值.是吧 004B33F5 8BD8 mov ebx,eax |
反编译代码比Delphi7多太多了...
刚才在翻VCL代码的时候发现这样一个结构体:就是我们刚才说的
1
2
3
4
5
6
|
StrRec = packed record codePage: Word ; elemSize: Word ; refCnt: Longint ; length: Longint ; end ; |
1
|
|
WideString
从名字看,我们就知道了它一个字符肯定占2个字节了.哈哈,看例子:
1
2
3
4
5
6
7
8
9
|
Procedure TForm3 . Btn1Click(Sender: TObject); Var S: WideString ; Begin S:= 'HuangJackyAAAAA' ; ShowMessageFmt( '%d' , [Length(S)]); //15 ShowMessageFmt( '%d' , [SizeOf(S[ 1 ])]); //2 ShowMessageFmt( '%d' , [SizeOf(S)]); //4 End ; |
是吧,每个字符是2个字节,变量还是存放的指针.像AnsiString那样看看它实际数据在内存中的组织:
偏移 | -4 | 0~长度-1 | 最后一个 |
内容 | 字符串长度 | 实际字符串内容 | $00 $00 |
它同样是用4个字节来存储长度,但是它每个元素的大小是2个字节,所以它最多只能存储2的30次方个字符.
是不是想跑去看它的内存呢?
长度是$1E??哈哈,长度要除2塞,因为这个长度是这个内存块的长度.
最后再多说一个:
PAnsiChar,PWideChar
这个就是C++里面的Char*,也就是末尾是0的那种字符,这个就比较单纯了,没有什么用专门的字节来存储长度,存储引用次数.所以很多地方我们能用PChar就用PChar,因为String类型的确很耗资源.
C++的人笑了,不要笑,CString一样有这个问题.
看个例子:
1
2
3
4
5
6
7
8
|
Procedure TForm3 . Btn1Click(Sender: TObject); Var S: PAnsiChar ; Begin S:= 'HuangJackyAAAAA' ; ShowMessageFmt( '%d' , [StrLen(S)]); //15 ShowMessageFmt( '%d' , [SizeOf(S^)]); 1 End ; |
看下内存,证明我没有忽悠人.
前面和它不沾边了吧,尾巴是0结尾了吧.
开篇时候提的问题,大家也知道区别了吧.平时不要看字符串简单,其实我们了解得还不够.
从上面看出来,字符串使用的使用第一个元素下标是从1开始的不是0.其他使用的注意事项打算写在下一篇文章里面.
我是DH,貌似该吃午饭了.
Delphi - 字符串 详解的更多相关文章
- Delphi指针详解
Delphi指针详解2007-12-04 06:08:57| 分类: DLL学习 阅读91 评论0 字号:大中小 订阅 大家都认为,C语言之所以强大,以及其自由性,很大部分体现在其灵活的指针运用 ...
- Delphi 关键字详解
Delphi 关键字详解[整理于 "橙子" 的帖子] absolute //它使得你能够创建一个新变量, 并且该变量的起始地址与另一个变量相同. var Str: ]; S ...
- SQL Server日期时间格式转换字符串详解
本文我们主要介绍了SQL Server日期时间格式转换字符串的相关知识,并给出了大量实例对其各个参数进行对比说明,希望能够对您有所帮助. 在SQL Server数据库中,SQL Server日期时间格 ...
- Swift_字符串详解(String)
Swift_字符串详解(String) 类型别名 //类型别名 fileprivate func testTypeAliases() { let index = String.Index.self p ...
- MS SQL Server 数据库连接字符串详解
MS SQL Server 数据库连接字符串详解 原地址:http://blog.csdn.net/jhhja/article/details/6096565 问题 : 超时时间已到.在从池中获取连接 ...
- Python变量和字符串详解
Python变量和字符串详解 几个月前,我开始学习个人形象管理,从发型.妆容.服饰到仪表仪态,都开始做全新改造,在塑造个人风格时,最基础的是先了解自己属于哪种风格,然后找到参考对象去模仿,可以是自己欣 ...
- C语言中字符串详解
C语言中字符串详解 字符串时是C语言中非常重要的部分,我们从字符串的性质和字符串的创建.程序中字符串的输入输出和字符串的操作来对字符串进行详细的解析. 什么是字符串? C语言本身没有内置的字符串类型, ...
- Delphi多线程详解
(整理自网络) Delphi多线程处理 1-1多线程的基本概念 WIN 98/NT/2000/XP 是个多任务操作系统,也就是:一个进程可以划分为多个线程,每个线程轮流占用CPU 运行时间和资源,或者 ...
- String 字符串详解 / 常用API
String 详解 / 常用API 简介 String 是不可改变的字符串序列.String 为字符串常量 StringBuilder 与StringBuffer 均为可改变的字符串序列.为字符串变量 ...
随机推荐
- JVM(1)——简介
网上流传着一段挺有意思的话-- 对于从事C或C++的开发人员来说,他们既是内存管理的最高权力的皇帝,也是最基础的劳动人民,担负着每一个对象生命开始到终结的维护工作,有点光杆司令的赶脚. 但对于java ...
- Bootstrap中轮播图
Bootstrap中轮播图插件叫作Carousel,为了清晰的表明每个标签在这里是什么意思,我把解释写在了下面的代码中. <!-- 以下容器就是整个轮播图组件的整体, 注意该盒子必须加上 cla ...
- Hiberante可配置参数
###################### ### Query Language ### ###################### ## define query language consta ...
- Intellij IDEA将工程打包成jar包并执行
打开File -> Project Structure -> Artifacts 点击“+”,选择“Jar”,选择Empty或From modules with dependencies, ...
- BZOJ1037 ZJOI2008生日聚会(动态规划)
设f[i][j][x][y]为安排了i个男孩j个女孩,后缀最大男孩-女孩数为x,最大女孩-男孩数为y的方案数.转移显然. #include<iostream> #include<cs ...
- P2483 【模板】k短路([SDOI2010]魔法猪学院)
题目背景 感谢@kczno1 @X_o_r 提供hack数据 题目描述 iPig在假期来到了传说中的魔法猪学院,开始为期两个月的魔法猪训练.经过了一周理论知识和一周基本魔法的学习之后,iPig对猪世界 ...
- 【题解】HNOI2008GT考试
这题好难啊……完全不懂矩阵加速递推的我TAT 这道题目要求我们求出不含不吉利数字的字符串总数,那么我们有dp方程 : dp[i][j](长度为 i 的字符串,最长与不吉利数字前缀相同的后缀长度为 j ...
- Reasons to use innodb_file_per_table
When working with InnoDB, you have two ways for managing the tablespace storage: Throw everything in ...
- com.mongodb.MongoException$CursorNotFound: cursor not found on server异常处理
java链接MongoDB处理大量数据时经常碰到cursor not found 的异常,其实是超时所致 Exception in thread "main" com.mongod ...
- js 禁止鼠标和键盘行为
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...