【三】 Symbian的描述符

所谓描述符,一定程度上等同于字符串。只不过与C++的字符串不一样,Symbian中的描述符都是用一个附加的整数描述其长度,而不是以'\0'做终结符。因此,描述符可以表达任意数据,字符串或者二进制串。

描述符体系

打开任何一本关于Symbian介绍的书,都可以看到Symbian描述符那复杂的继承体系。它的基类是TDesC,顾名思义,T是代表它是T类,后缀C表示它是一个常量,其中数据无法修改。因此,它只是定义了一些字符处理的方法,包括查找、匹配、取子串等,而不包括任何修改其中数据的接口。可修改的描述符类,都是派生自TDes,它是TDesC的子类,额外提供了拷贝、清零、追加之类的接口。
当你需要在栈上分配一个描述符,你可能需要用到TBuf或者TBufC类。它们都是模板类,接受一个int型参数作为长度信息。从名字可以一目了然的看出其中区别,带C的自然是常量,它一次性在栈中分配好所需的资源,并且同时完成赋值和初始化工作,一经分配,则不能再次修改。而不带C的TBuf,在构造时仅是在栈中预留好所需空间,此后可以在此空间范围内,任意的修改所需内容。从内存分布来看,TBufC对象在真实的字串信息前,还放了一个32位整数,它的前4bits存放类型信息,后28bits存放长度信息,也就是说一个TBufC对象最多包含256M长度的字符串,这已经绝对足够了。而TBuf对象,除了TBuf所包含的内容外,还额外加入了一个max-length的整数在长度信息后,它表示预分配了的内存长度,而length则用于表示真实有效的数据长度。
除了栈,更多的描述符长度不是在编译期能够确定的,需要在堆上动态的进行分配,这项任务,就交由了HBufC来完成。HBufC也包含三项数据,前两项与TBuf一致,4bits类型 + 28bits真实长度 + 1×××的分配长度。但最后一项是一个指针,它指向堆中的某个位置,在这个位置,开辟了预分配长度的字符串空间。但HBufC的基类不和TBuf一致,而是于TBufC相同,这和它C的后缀表里如一,代表它只具有一些非数据修改性质的接口。这样的设计,一定会引发一系列的疑问,为什么明明又有max-length信息,又具有length信息,却是一个不可变的描述符对象?如果需要动态改变堆中描述符的内容,该使用什么样的类?
所有这些疑问,都可以通过TPtr这个类来解答。单纯的从内存数据来看,TPtr与HBufC完全一致,但从实际逻辑来看,HBufC中的指针,仅仅可能指向堆中的数据,而TPtr中的指针可以指向一个堆数据,也可以指向一个栈数据,这完全取决于你用什么对象来初始化它。如果用一个TBuf来初始化,那么就指向栈中,用HBufC来初始化,就指向了堆中,整个一墙头草。但不论是指向堆还是指向栈,TPtr对所指向的数据都仅拥有使用权,而不具有控制其生死的权利,该数据需要通过其原始的控制者,TBuf或者HBufC等来负责管理。很多时候,TPtr都是作为HBufC的一个帮手而存在,当你需要修改HBufC中的字符数据时,调用Des()接口,从HBufC华丽的转身为TPtr,TPtr没有C的后缀,这意味着它秉承了TDes的能力,可以修改其中的数据。我一直不理解Symbian为什么要设计一个HBufC类,而不是HBuf类,唯一可以想到的解释就是,由于TPtr的存在,可以解决修改堆描述符数据这件事情,而不需要再多实现一些接口,虽然有点牵强,但我还是一直用这解释自欺欺人。
TPtr还有一个孪生兄弟TPtrC。和TBufC与TBuf的关系类似,TPtrC去掉了max-length这个域,分配长度即使用长度。TPtrC所有的设计逻辑,都与TPtr一致,指向堆或栈对象,只使用不管理资源,等等。它应用的最广泛的场合,就是用于表达子串。比如TBuf对象希望取出其中前10个字符给调用者使用,它就会返回一个TPtrC对象,它指向HBufC的字符位置,但仅具有10个长度,既可以控制长度,又可以保证其中数据不被修改,一举两得一石二鸟。
到此为止,描述符的整个构架算是完整了,既有栈的,又有堆的;既有可修改的,有包含不可变的;既有表达整体的,又有表征局部的。但Symbian本着买一送一,挥泪大馈赠的态度,还提供了一个RBuf类。这是一个R类,并且没有C后缀。它通过Create接口在堆上分配数据,用Release或Close析构所掌握资源,从本质上来看,它就是HBufC的一个R版。但RBuf的基类是TDes,因此直接提供了更为丰富的数据修改接口,不需要转身成TPtr来处理。并且,RBuf屏蔽了字符串为NULL和为空的区别,有的时候,在使用HBufC需要不停的判定是否为NULL或者为空,而用RBuf则不需要,NULL即空,空即NULL。但RBuf的继承体系更深,并且可以想象,它的一些操作会再次封装一些额外的检测操作,可能效率上会有一丁点的降低(只是猜测,有兴趣可以做实验证实...)。从RBuf和HBufC的区别,你也可以从中推断出两者最适合的使用场景。HBufC其实最合适的就是应该本着其C的本质来做,适合于分配了不再修改的场合,比如从一个已有的描述符拷贝出新的描述符,此时返回的往往就是HBufC。而RBuf更适合反复修改的场合(不然白瞎了叫它一声Buf...),在这样的场景下,其接口使用起来更为的简单和明了。。。

编码

前面提到的所有描述符,其实都不是真实的类,而是一个typedef。在非内核模式的时候,所有的描述符,如TDesC,其真实的实现是TDesC16,在内核模式的时候,则是TDesC8。还是看名取义,带8的是单字符1个字节的描述符,带16的是宽字符2字节的描述符。在非内核态的时候,统一使用16位的描述符作为默认值,是为了兼容unicode编码,帮助在不同语言下进行开发。大部分的系统API,提供的都是接受TDesC这样typedef的接口,其实也就是unicode-16的16位描述符。但在一些io相关的接口,都是接受8结尾的单字符描述符,以兼容不同的数据格式。单字符描述符通常不会对编码有任何约束,可以是二进制流,可以是utf-8,可以是一般的ascii码。具体是什么,逻辑需要调用者自己来维护。为了将io读入的数据传递给一些系统API,往往就需要将8位描述符转成16位描述符。这种转换和编码有密切联系,如果只是一般的ascii串(或者其他编码的ascii部分...),可以使用TDes的Copy接口,从8位拷贝到16位,或者从16位拷贝到8位。从8位拷贝的16位,第一个字节填充对应的8位字符的内容,第二个字节填充的是'\0',就是全部为0。而从16位到8位,可想而知,后一个字节的内容被截取抛弃。但如果是一些复杂的编码转换,比如utf-8的字符流转成系统所需的unicode-16,那么就需要用到CnvUtfConverter,它负责在不同的字符集中做转换。

其他字符类型类

看到Symbian的描述符,最疑惑的不仅仅是那套复杂的继承体系,还有_L和_LIT这样的宏。打开_LIT这个宏,你可以看到,它其实就是定义一个TLitC类型的const static常量字符串。从意义上来说,通过_LIT,可以将一些常用的字符串作为常量存在,使其不会反复构造和析构,是空间换时间的策略;从接口上看,它重载了很多转型运算符operator (),可以转身成为TDesC的各个版本,与该继承体系兼容;而从内存实现上来看,它存放的是:C++字符串的长度(除\0) + 原汁原味的C++字符串(就是\0结尾的一坨short int或者char数组...),通过这样的结构,一方面可以和Symbian的描述符表示相一致,又可以享用C++的原始支持,一举两得。
相比_LIT的华丽,_L这个宏就土鳖不少,代表了旧生产力的落后。它其实,就是定义一个TPtrC,TPtrC中的内容指向了一个常量的数组(typedef后叫做TText...),这个常量数组,其实就是有一个char或short int的数组转型而成,也是原汁原味的C++字符串。从本质上来看,TPtrC扮演这个角色,完全是在人手短缺时的友情客串,它本不应该来做这件事情,因为其内部是通过一个指针来指向真实的字符空间,很多操作都经过多一次的取址操作,降低了效率;而TLexC,则是量身打造精心包装天生大明星,它优化掉了那个作梗的指针,提高了效率。所以摒弃_L,拥抱_LIT,是所有Symbian教学都会呼吁的内容,还是合情合理的。。。
还有一个常用的和字符串相关联的东西,就是TLex类。它做的工作,就是大名鼎鼎的string-parsing。给它一个描述符,它可以还你一个×××数抑或是浮点数。TLex对数的解析,本质上还是基于ascii编码的,你给它的描述符编码,需要兼容ascii标准,不要拿个全角的数字为难它,它会罢工的。。。

转载于:https://blog.51cto.com/duguguiyu/362832

Symbian手记【三】 —— Symbian的描述符相关推荐

  1. SURF C++代码 详细阅读(三)—— SURF描述符

    SURF C++代码详细阅读(三) 3 SURF描述符 3.1 构造函数 3.2 获取描述符函数(主要) 3.2.1 获取主方向 3.2.1 计算描述符(旋转) 阅读(二)获取了特征点,接着针对每个特 ...

  2. Symbian编程总结-基础篇-描述符(2)-TDesC8与TDesC16之间的互转

    1.使用Copy _LIT8(KTestStr, "This is a string"); TBufC8<50> buf(KTestStr); TBuf<100& ...

  3. symbian os:描述符

    // // 这是我的第二篇博文,开始学习Symbian c++ // 同大家一起努力 // 谨以此文献给我的最爱 YY女孩(YY 可别想坏了哦) // // --------------------- ...

  4. linux kernel的中断子系统之(三):IRQ number和中断描述符【转】

    转自:http://www.wowotech.net/linux_kenrel/interrupt_descriptor.html 一.前言 本文主要围绕IRQ number和中断描述符(interr ...

  5. linux kernel的中断子系统之(三):IRQ number和中断描述符

    原文地址 http://www.wowotech.net/linux_kenrel/interrupt_descriptor.html linux kernel的中断子系统之(三):IRQ numbe ...

  6. linux 输出重定向_Linux--文件描述符和stdin,stdout,stderr

    基本概念 1. 文件描述符 总览: 当一个程序成功向操作系统请求访问一个打开的文件, 内核会返回一个指向内核中全局文件表(global file table)中的入口点(entry)的文件描述符. 文 ...

  7. [转帖]linux文件描述符文件/etc/security/limits.conf

    linux文件描述符文件/etc/security/limits.conf https://blog.csdn.net/fanren224/article/details/79971359 需要多学习 ...

  8. linux 反弹shell(一)文件描述符与重定向

    0X00 前言 由于在反弹shell的过程中有一些非常精简的语句,但是一直没有深入理解,只是作为一个伸手党/搬运工,于是下定决心要将其弄明白,而这里面最难的也就是文件描述符和重定向的部分,因此我特地写 ...

  9. linux存储--文件描述符fd与FILE结构体(二)

    文件描述符fd 对于linux而言,所有对设备(对于linux而言,一切皆文件)和文件的操作都使用文件描述符来进行的. 文件描述符是一个非负的整数,它是一个索引值,指向内核中每个进程打开文件的记录表. ...

  10. linux存储--文件描述符以及file结构体(一)

    一.什么是文件描述符 在Linux下一切皆文件,对于内核而言,所有打开的文件都通过文件描述符引用,文件描述符是一个非负整数,当打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符.当读. ...

最新文章

  1. EF 4.1+MVC3+Jquery Ajax+Json.Net+JqueryUI+IUnitOfWork+Repository 学习DEMO(暂停更新)
  2. java adt怎么打开项目,如何在Eclipse中打开Android Studio项目?
  3. 一文弄懂SSD目标检测算法
  4. 一步步学习微软InfoPath2010和SP2010--第十四章节--高级选项(3)--重新链接表单
  5. ASP.NET Core Web API 最小化项目
  6. 2021年算法工作总结
  7. 17 MM配置-BP业务伙伴-定义业务伙伴角色
  8. 关于Bus的几个问题
  9. mysql ddl 失败_PHP加载mysql DDL会失败
  10. OpenCV_Find Basis F-Matrix and computeCorrespondEpilines(获取一对图像的基础矩阵及对应极线)
  11. 如鹏网.Net高级技术4.String特点及常用方法
  12. 人工智能助力网络金融反欺诈,声纹识别受追捧
  13. SAP采购计划协议(SA)中的计划行统计清单
  14. excel之countifs函数
  15. oracle 12c导入dmp文件(实践)
  16. openmv一些常见问题与心得总结
  17. 利用FFT 及 IFFT实现傅立叶正反变换
  18. STC89系列单片机看门狗的使用及应用程序
  19. 布尔代数(Boolean Algebra)
  20. uniapp商城前端源码下载/uniapp多店铺PHP商城源码下载

热门文章

  1. LeetCode-3Sum -三数求和-有序数组扫描
  2. XSD(XML Schema Definition)学习笔记
  3. 这段js代码得拯救你多少时间
  4. Javascript 操作元素Class属性的问题
  5. 工作站的windows server 2008 终于安装好了
  6. Notepad++便签模式
  7. Kafka生产者源码解析
  8. Java程序员一些常用的日志和其他Linux命令(自用)
  9. 在每个运行中运行多个查询_linux系统中运行级别介绍
  10. kbmmw 与extjs 通过JSON Base64 显示图片