【转】symbian 描述符(上)

转自http://www.cppblog.com/franksunny/archive/2007/10/19/34622.html

 

 

接触 Symbian 已经一个半月多了,自从上个月熟悉了框架之后,一直都不敢再写什么东西了,因为没有经历过代码怎么可能写得出东西呢?起笔犹豫了很久,打算涉足 Symbian 与标准 C++ 的一个不同点——描述符。希望自己能够借这个机会搞清楚描述符这个东西。

 

一、总介

由于手机系统的资源区别于 PC ,为此为了更好的在内存受限设备上处理内存缓冲, Symbian 提供了独特的描述符,用以存储和操作字符串、以及管理二进制数据和其它串行化的复杂对象( serialized compound objects )。

Symbian OS 的很多 API 调用的参数都是描述符,同时 Symbian 也为描述符提供了很多的操作函数。但是描述符本身其实就是一个封装了数据及其长度的内存块类。作为字符串处理类,它与标准 C++ 的以 '/0' 结束符的字符串有区别,即它没有结束符;描述符在处理字符串和二进制数据时又有不同:首先 Symbian 使用 Unicode ,所以字符串通常存于 16 位描述符中,而二进制数据存储于 8 位描述符中(通常在底层通信中用的都是 8 位的描述符);其次如果描述符中包括二进制数据,则描述符的字符串操作方法不可用(我的理解是可以用,但是不能当字符串来用,所以也就没有意义了。至于处理串行化对象,本人没有接触所以暂时略过)。

 

二、描述符类型分类及其相互关系

描述符主要有四类,但是我们通常将文字常量也作为描述符的一类,所以就有了五类,以下就是常见分类:

·       抽象类(Abstract ):(TDesTDesCTdes8TdesC8 ),其他描述符的基类,仅提供接口和基本功能,不能被实例化,一般只用作函数的参数。

·       文字常量(Literal ):(TlitC_LIT() ),用于存储文字字符串(literal string ),即C 中字符串常量,通常使用_LIT() 这种方式(当然还有_L()_L8() 的描述方式,但都不提倡用)。

·       栈类(Buffer ):(TbufTbufCTbuf8TbufC8 ),数据存储于栈上,最基本的描述符变量类型,大小在编译时确定,包含描述符本身数据,使用最为普遍。

·       堆类(Heap ):(HbufCHbufC8 ),数据存储于堆上,大小在运行时确定,也就是是用来处理动态申请的描述符类。在C/C++ 中用过动态内存的都知道,动态内存是啥回事,这里堆类描述符用的时候,也是差不多,由于堆描述符没有构造函数,所以只能声明为指针类型,通过堆描述符类内静态函数NewL 方法申请内存,具体方法如下

HBufC* errorTitleCode = HBufC::NewLC(50);

HbufC* unUseCode = NULL;

·       指针类(Pointer ):(TPtrTPtrCTPtr8TPtrC8 ),本身不包含描述符数据,但是包含长度数据,而且还包含一个指向位于描述符之外数据的指针。

从以上分类可知,描述符有 8 位和 16 位宽度的区别,还有可修改和不可修改的区别,具体的区别我从内存的角度出发列表如下:

具体类型

类型(4b

当前长度(28b

最大长度( 32b

Buffer

TDesC8

 

Yes

TDesC

 

Yes

TDes8

 

Yes

Yes

TDes

 

Yes

Yes

TBufC8

0

Yes

ByteBuffer

TBufC

0

Yes

WordBuffer

TBuf8

3

Yes

Yes

ByteBuffer

TBuf

3

Yes

Yes

WordBuffer

TPtrC8

1

Yes

32 位指针

TPtrC

1

Yes

32 位指针

TPtr8

2

Yes

Yes

32 位指针

TPtr

2

Yes

Yes

32 位指针

HBufC8

0

Yes

ByteBuffer

HBufC

0

Yes

WordBuffer

注:

1、  表中空出的内容,我暂时还不知道具体的值是多少。其中的 b bit 的意思;

2、  在实际操作中,定义的描述符长度和内存实际使用长度会有不一致问题,原因是描述符也是按4字节进行边界对齐的

由如表所示的内存关系可能显得有点乱,如果能将每个类用 UML 类图(包括详尽的成员变量和成员函数,类的头文件在 e32des16.h e32des8.h 中)来表示就更直观了,在 Symbian 官方网站有一张类简图,我先将此作为继承关系的简图在这里作为演示用

 

三、描述符的使用

介绍到这里应该具体讲每一个描述类的使用了,我发现有两篇中文文档整理的很好,在这里,我只做一些验证性的介绍,读者可以参阅我在文章后列出的两篇文档。由于要略过不能实例化的抽象类,且按照从简单到复杂的过程来叙述:

 

1、  文字描述符常量

a _LIT() 可以生成个常量名,以便以后重复使用,例如

_LIT(KMyFile, "c:/System/Apps/MyApp/MyFile.jpg");

_LIT() 宏的结果(就是上面的 KMyFile )实际上是个文字描述符( literal descriptor TLitC ,它可以在任何使用 TDesC& 的地方使用。(但是 TlitC 已经不推荐使用了)。

b _L() 可以生成一个指向字符值的地址( TPtrC ),它经常被用来传递字符串到函数中(包括描述符的构造函数和格式化函数);同理 _L8() 则可以生成一个指向二进制数据的地址( TPtrC8 )举例如下:

// 常用的通知函数

NEikonEnvironment::MessageBox(_L("Error: init file not found!"));

// 数字转字符串

TBuf16<20> buf;//

TInt iNum = 20;

buf.Format( _L( "%d" ) , iNum  );

 

2、  栈描述符

栈类描述符声明时必须指定描述符的最大长度,否则无法声明和定义,下面举例

1 :构造

// 直接从字符串中构造

_LIT(Ktext, "TestText");

TBufC<10> Buf (Ktext);

// 或从字符串赋值

TBufC<10> Buf2;

Buf2 = Ktext;

// 从已有的对象中生成新的 TBufC

TBufC<10> Buf3(Buf2);

TBufC<n> 一般用来存储文本数据,而 TBufC8<n> 则用来存储二进制数据。尽管这里的对象表示数据是不能被修改的(因为有个后缀 C 代表了常量的意思),但仍然有两种方式可以用来修改数据内容:这里的数据可以用赋值的方式替换掉;使用 Des() 函数构造出一个 TPtr 对象,这样就可以用它来修改数据。

2 :修改数据

_LIT(Ktext , "Test Text");        

_LIT(Ktext1 , "Test1 Text");

_LIT(KXtraText , "New:");

_LIT(NewText , "New1");

_LIT(NewText1 , "New2");

TBufC<10> Buf1 ( Ktext );//Buf1 长度为 9 内容 Test Text

TBufC<10> Buf2 ( Ktext1 );//Buf2 长度为 10 内容 Test1 Text

 

// 通过赋值的方式改变数据

Buf2 = Buf1; //Buf2 长度变为 9 内容 Test Text

 

// 通过使用 Des() 生成指针改变 TBufC 的数据

TPtr Pointer = Buf1.Des();

// 删除后四个字符

Pointer.Delete(Pointer.Length()-4, 4 ); //Buf1 长度变为 5 内容“ Test

                               // 但是内存应该没变

// 增加新的数据

Pointer.Append(KXtraText);//Buf1 长度为 9 内容为“ Test New :”

 

// 也可以使用下列方式改变数据       

TBufC<10> Buf3(NewText);

Pointer.Copy(Buf3);//Buf1 长度为 4 ,内容为 New1

// 或直接从字符串里获得数据

Pointer.Copy(NewText1);//Buf1 长度为 4 ,内容为 New2

 

以上介绍的是不可修改的栈描述符,而可修改的描述符就不用通过那么复杂的方法来实现修改,它直接可以用 Copy Delete 等 方法,但是无论可修改的还是不可修改的,一旦指定最大的数据长度后,最大长度就不能进行修改了。修改的只是数据内容,而数据内容修改的受限条件是不能超过 声明或定义时的最大长度。(个人以为从内存角度来说,不可修改类型的缺少最大长度,所以严格上来说为了减少错误,修改数据内容是不允许的)

 

3、  堆描述符

堆描述符虽然都是不可修改类型的,但是它仍然具有构造和修改,与栈描述符不同的是:首先对内存需要显示释放,其次是堆描述符没有最大长度的限制,任何时候都可以用 ReAlloc ()函数重新申请分配。具体见示例:

       // 1 、构造

       // 有两种方式来生成一个 Heap Descriptor

       // 第一种方式用 New(),NewL(), NewLC()

       // 如下操作便可以构建一个存放数据的空间,空间为 15 ,不过目前大小为 0

       HBufC * Buf = HBufC::NewL(15);

      

       // 第二种方式是采用 Alloc() AllocL() AllcLC() 来处理,

       // 不过这是已经存在的数据的管理方式。新的 Heap Descriptor

       // 可以自动的根据这个内容来构造。

       _LIT (KText , "Test Text");

       TBufC<10>  CBuf = KText;

       HBufC * Buf1 = CBuf.AllocL();

       CleanupStack::PushL(Buf1);

      

       // 2 、修改

       // 下面是通过赋值方式改变其数据的方法

       _LIT ( KText1 , "Text1");

       *Buf1 = KText1;

      

       // 通过可修改指针来改变数据的方式

       TPtr Pointer = Buf1->Des();

       // 添加数据

       Pointer.Delete(Pointer.Length() - 2, 2);

       // 删除数据

       _LIT ( KNew, "New:");

       Pointer.Append(KNew);

 

       // 3 、重新申请内存

       Buf1 = Buf1->ReAllocL(KText().Length() + KNew().Length());

       CleanupStack::PushL(Buf1);

 

       // 4 、释放内存

       // 直接用 delete

       delete Buf;

       Buf = NULL;

       // 如果在使用 NewL ReAllocL 等异常函数后我们使用清除栈压入的话

       // 那么我们也可以用清除栈来释放内存

       CleanupStack::PopAndDestroy();

       Buf1 = NULL;

 

注:关于以上用清除栈的方式,个人只是猜测,因为对 Symbian 的异常处理三部曲,至今仍没有很好的掌握,所以如果有什么误用还望指点。

 

4、  指针描述符

其实关于指针描述符,我们在上面已经用过可修改的指针 TPtr 了,下面返璞归真,从 TPtrC 的构造开始介绍使用

       // 1 TBuf TBufC 构造出 TPtrC 对象

       _LIT(KText , "Test Code");

       TBufC<10> Buf ( KText );

       // 或者为 TBuf<10> Buf ( KText );

       // Creation of TPtrC using Constructor

       TPtrC     Ptr (Buf);

       // Creation of TPtrC using Member Function

       TPtrC     Ptr1;

       Ptr1.Set(Buf);

 

       // 2 TText* 构造 TPtrC

       const TText* text = _S("Hello World/n");

       TPtrC ptr(text);

       // 或者

       TPtrC Ptr2;

       Ptr2.Set(text);

       // 如果要存储 TText 的一部分数据,我们使用下列方法

       TPtrC   ptr4(text, 5);

      

       // 3 从另一个 TPtrC 中构造 TPtrC

       const TText * text1 = _S("Hello World/n");

       TPtrC Ptr3(text1);

       // 从一个 TPtrC 中获得另一个 TPtrC

       TPtrC p1(Ptr3);

       //

       TPtrC p2;

       p2.Set(Ptr3);

以上是不可修改的 TPtrC 的构造,相对应的也有可修改的 TPtr 的构造,不过我们下面省略了用 Set() 函数的构造方法

       // 1 通过 TBufC,HBufC Des() 方法获取

       _LIT(KText, "Test Data");

       TBufC<10> NBuf ( KText );

       TPtr     Pointer = NBuf.Des();

 

       // 2 通过指定内存区域和大小来生成

       const TText * Text = _S("Test Second");

       TPtr    Pointer1((TText*)Text, 11, 12);

 

       // 3 通过另一个 TPtr 对象来生成

       TPtr     Pointer2 ( Pointer );

对于可修改的 TPtr 虽然前面用过,但是我们在这里在简单的添加两个例子加深下印象,并且说明指针修改的始终是它指向的描述符:

       // 1 改变已有 TPtr 数据的方式:赋值和 Copy() 方法  

       _LIT(KText, "Test Data");

       _LIT(K1, "Text1");

       _LIT(K2, "Text2");

       TBufC<10> NBuf ( KText );//NBuf 内容为“ Test Data

       TPtr     Pointer = NBuf.Des(); //Pointer 指向 NBuf 的内容       

       Pointer = K1; // NBuf 内容为“ Text1

       Pointer.Copy(K2); // NBuf 内容为“ Text2

      

       // 2 、直接通过修改长度改变数据内容

       Pointer.SetLength(2); // NBuf 内容为 "Te" 注:实际内存的内容应该没变

 

5、  抽象描述符

抽象描述符,没有什么好说的,正如前面所说,只用在函数的形参中,通常要强调参数是不可修改的,就用 const TDesC& 表示,可修改的参数用 TDesC& 表示。

 

四、常用 API 函数罗列

下面再对描述符的几个常用修改和不可修改 API 函数加以罗列

不可修改型:

// 获取属性类

Length() Size()

// 查找、比较类

Compare() Locate()LocateReverse ()Find()Match()

// 取描述符子串指针类

Left() Right()Mid()

可修改型:

// 增加、插入、删除类

Insert() Delete()Append()Replace() Trim()

// 赋值类

Zero() Copy()Num()Format()

 

本文涉及的两篇文档

Nokia 官方培训(Symbian4300) 笔记()—Descriptors (该文链接google 里面找)

中文 Descriptors 的使用

http://wiki.forum.nokia.com/index.php/%E4%B8%AD%E6%96%87_Descriptors%E7%9A%84%E4%BD%BF%E7%94%A8#TPtr.E7.9A.84.E4.BD.BF.E7.94.A8

后 记:本想把涉及描述符的转换也整理在一篇文章中的,但是后来发现整理完概念和使用已经消耗了我一天多时间了,晚上部门要去喝茶,为此暂时到这里,明天周末 在整理转换问题。由衷感谢单位给我那么多时间在工作中学习,想想以前第一份工作时,在单位看书都要被老板说的历史,发觉自己现在真的蛮幸运的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值