描述符浅析

一、不可修改的描述符(基类TdesC)
通过length()方法获取描述符长度。实际上描述符的长度都是由4个字节即32位来保存的,但实际上,其中的4位留做他用,只有28位用来保存描述符的长度,这样的话一个描述符的最大长度就是2 28字节,即256MB。而这4位用来表示描述符的类型,目前共有5个派生描述符类型,足够用。
 
对于所有的描述符,要访问其中数据,通过 基类 TdesC 的非虚方法 Ptr (),获取指向数据的指针。
 
定义了一系列成员方法:length()、size()、ptr()、find()、match()、compare()、left()、locate()等
 
二、可修改的描述符(基类TDes,它继承自TDesC)
TDes类有一个额外的成员变量,用来保存描述符现有内存情况下所能存储数据的最大允许长度。而TDes类的MaxLength()方法返回的就是这个值。
 
TDes类定义了修改字符串数据的一系列方法:添加、填充、格式化描述府数据等
 
所有上述方法都不会分配内存,如果想使用上述方法来扩展描述符中数据的长度,就像Append(),在调用方法之前必须保证有足够的内存可用,否则失败。
 
注意:TdesC和TDes都是抽象类,不能用它们来进行实例化。我们使用描述符时,使用的都是它们的派生类实例。即基于两种布局的描述符:指针描述符(这种描述符中保存了指向字符串存储位置的指针)和缓冲描述符(字符串是其对象的一部分)。
 
三、指针描述符:
指针描述符的字符串数据和描述符对象本身是分离的,可以储存在ROM中、堆上或栈上。而保存着数据的内存并不属于描述符,也不通过描述符来管理。因此,如果数据保存在堆上,那么内存的创建、必要时的重新分配还有销毁都要使用堆描述符指针(HBuf),如果指针描述符引用了基于栈的字符串,那么相应的内存就被分配到栈上了。指针描述符本身往往是被分配到栈上的,但它们也可以被分配到堆上,例如,它们可以作为一个CBase派生类的成员变量。
1、不可修改的指针描述符(TPtrc), 描述符对象本身大小是 2 个字

                                                                     

TPtrc的 数据可以被访问但却无法被修改:即描述符中数据是恒定的。所有定义于Tdesc基类的不可修改的操作对于TPtrc的对象都是可以访问的。
 
该类还 定义了一系列构造函数,从而允许TPtrc能够从其他描述符、指向内存的指针或者零终结符的C语言字符串创建。
 
指针本身可以改变以指向不同的字符串数据。使用Set()方法可以改变指针的指向。
2、可修改的指针描述符(TPtr), 描述符本身大小是 3 个字

  

TPtr是为访问、修改字符串或二进制数据而设计的可修改的指针描述符类。
 
该类 定义了若干构造函数,能以包含内存地址的指针为参数,并设置适当长度和最大长度来构造对象。
 
另外该类还提供了一个赋值操作符operator=(),该操作符可以将数据复制到对象指针所引用的内存中去(从其他可修改的指针描述符、不可修改的指针描述符或零终结符的字符串复制数据)。如果复制的数据长度超出了描述符的最大长度,那么将产生一个系统错误。
 
另外和TPtrc类似,也提供了一个Set()方法,用于指向其他的数据。
注意:不要混淆Set()和operator=()。 Set ()将描述符重置为指向新的数据区域(相应的修改了长度和最大长度这两个成员变量),而 operator =()仅仅将数据复制到已经存在的描述符,并可能修改描述符长度,而 不会修改其最大长度。
 
四、基于栈的缓冲描述符
同样分为可修改的和不可修改的,字符串数据是描述符对象的一部分。这些字符串对于定长的字符串和相对较小的字符串(最多256个字符)都很有用。 这些描述符都是基于栈的,当描述符与其创建者有着一致的生命周期时,应当使用这种描述符。
 
1、   TbufC<n>
用来保存不会改变的字符串或二进制数据,派生自TbufBase类,n代表分配的 适当数据区域大小。(相等或稍大)
 
定义了若干构造函数,从而使得不可修改的缓冲区能够从任何其他描述符的附件或者零终结符的字符串构造。它们也可以创建为空的,待以后填充。尽管数据是不可以修改的,但缓冲区的内容却可以使用类中定义的 赋值操作符全部替换掉。替换的数据可以是另一个不可修改的描述符或零终结符的字符串。
 
另外,该类也定义了一个 Des ()方法它会为缓冲区所表示的数据返回一个可修改的指针描述符。因此,除了赋值操作符完全替换外,还可以通过这个可修改的指针描述符来修改。
 
2、   Tbuf<n>
这里n代表缓冲区最大允许长度。
 
五、基于堆的缓冲描述符
对于不放在ROM中和由于太大而无法保存在栈内的字符串数据,可以使用基于堆的描述符。
当描述符可能比其创建者具有更长的生命周期时可以采用基于堆的描述符。
HbufC:
注意:该类导出了一组静态 NewL ()函数,用来在堆上创建缓冲区。这些函数遵从两阶段构造模型,因为在空闲内存不足时可能发生异常退出。该类没有公共构造函数,所有的堆缓冲区必须采用其中某个NewL()方法来构造(或者通过 TdesC 类的 Alloc ()或 AllocL ()方法构造,通过该类你可以做出任何描述符的HbufC附件)
 
缓冲区数据虽不允许修改,但可通过 赋值操作符,整个进行替换。
还可以通过 Des ()方法操纵基于堆的操作符创建一个可修改的指针描述符 TPtr,这与TbufC是一样的。
 
六、字面描述符( 被编译放入 ROM 的常量描述符
通过一组宏来创建,这些宏定义在e32def.h头文件中。
字符宽度无关的宏_L,_S和_LIT的隐式和显式定义都是对应相同的。例如,_L在Unicode构建版本中等价于_L16,而在ASC码中等价于_L8。
1、_LIT
最高效、最被提倡使用的symbian os字面常量。
注意:TlitC16和Tlit8不是派生自TdesC8或Tdesc16,但他们和TbufC8和TbufC16具有相同的内存布局,所以 这些类型的对象可以应用到任何使用 TdesC 的地方
对一个_LIT常量使用sizeof(),返回的将是对应的TlitC对象的尺寸,即描述符内容的大小,单位是字节,再加上8个额外的字节(一个保存长度的Tuint和NULL终结符),如果你想使用栈的缓冲区,就必须把他们计算在内。
2、_L

好处是不必为它想一个名字。使用_L会创建临时TPtrC类型的临时开销。

 

补充:

文字描述符(Literal Descriptors)
在这里面定义了一些宏和一些类,这些类的对象是常量描述符,它们被编译器创建在只读内存上。
这里面又很多比_L高效的宏,但是为了系统兼容性考虑,我们仍然保留了_L宏。
一、系统定义的描述符:
KNullDesC16
_LIT16(KNullDesC16,"");
表示空或者无文本的16位格式描述符。

KNullDesC8
_LIT8(KNullDesC8,"");
表示空或者无文本的8位格式描述符。


KNullDesC
_LIT(KNullDesC,"");
表示空或者无文本的描述符。在non-Unicode编码系统中,表示8位格式描述符;在Unicode编码系统中,表示16格式描述符。

二、宏
(1)
_L8
#define _L8(a) (TPtrC8((const TText8 *)(a)))
不管系统什么编码格式,该宏创建一个8位格式的常量文本。

_L16
#define _L16(a) (TPtrC16((const TText16 *)L ## a))
不管系统什么编码格式,该宏创建一个16位格式的常量文本。

_L
#if defined(_UNICODE)
typedef TText16 TText;
#define _L(a) (TPtrC((const TText *)L ## a))
...
#else
typedef TText8 TText;
#define _L(a) (TPtrC((const TText *)(a)))
...
#endif
根据系统具体编码格式,动态确定创建一个8位或16位格式的常量文本。

(2)
_LIT8
#define _LIT8(name,s) const static TLitC8<sizeof(s)> name={sizeof(s)-1,s}
使用指定的名字和文本内容创建一个TLitC8<TInt>类型的常量描述符。

_LIT16
#define _LIT16(name,s) const static TLitC16<sizeof(L##s)/2> name={sizeof(L##s)/2-1,L##s}
使用指定的名字和文本内容创建一个TLitC16<TInt>类型的常量描述符。

_LIT
#if defined(_UNICODE)
#define _LIT(name,s) const static TLitC<sizeof(L##s)/2> name={sizeof(L##s)/2-1,L##s}
#else
#define _LIT(name,s) const static TLitC<sizeof(s)> name={sizeof(s)-1,s}
#endif
对于non-Unicode编码系统,创建一个TLitC8<TInt>类型的常量描述符;对于Unicode编码系统,创建一个个TLitC16<TInt>类型的常量描述符。

(3)
_S8
#define _S8(a) ((const TText8 *)a)
创建一个8位的常量串。

_S16
#define _S16(a) ((const TText16 *)L ## a)
创建一个16位的常量串。

_S
#if defined(_UNICODE)
typedef TText16 TText;
...
#define _S(a) ((const TText *)L ## a)
#else
typedef TText8 TText;
...
#define _S(a) ((const TText *)a)
#endif
根据不同的系统,创建一8位或16位的常量串。

通过观察这三种宏的具体定义形式,发现它们的不同点:
_L产生的对象没有名字,它的类型是TPtrC
_S产生的对象也没有名字,它的类型是const TText *
_LIT产生的对象有名字,它的类型是const static TLitC
相同点:
对象都是常量不可变的。
它们都被创建在只读内存里。


三、类
(1)
Class TLitC8
对象表示一个8位格式的常量描述符,没有构造函数,使用宏_LIT8创建对象。
Class TLitC16
对象表示一个16位格式的常量描述符,没有构造函数,使用宏_LIT16创建对象。
Class TLitC
对象创建一个8位或16位格式的常量描述符,没有构造函数,使用宏_L创建对象。

这三个类均定义了4个操作符重载"()",这4个重载操作符的返回值不同。

(2)
Typedef __TRefDesC8
typedef TRefByValue<const TDesC8> __TRefDesC8;
表示一个指向TDesC8描述符的引用,通过TLitC8::__TRefDesC8()创建。

Typedef __TRefDesC16
typedef TRefByValue<const TDesC16> __TRefDesC16;
表示一个指向TDesC16描述符的引用,通过TLitC16::__TRefDesC16()创建。

Typedef __TRefDesC
typedef TRefByValue<const TDesC> __TRefDesC;
通过TLitC::__TRefDesC()创建。

Class TRefByValue
TRefByValue<class T> //模板类

四、使用宏_LIT
_LIT(KSomeBuildIndependentLitText,"qwerty"); //create literal
iEikonEnv->InfoMsg(KSomeBuildIndependentLitText);

上面的代码相当于:
const static TLitC<7> KSomeBuildIndependentLitText;
iEikonEnv->InfoMsg(KSomeBuildIndependentLitText);

上面的代码可以如果使用宏_L的话,可以这样修改:
iEikonEnv->InfoMsg(_L("qwerty"));

同样的,对于16位格式描述符和8位格式描述符,可以如下定义:

_LIT16(KSomeLIT16Text,"qwerty");
相当于:const static TLitC16<7> KSomeLIT16Text;

_LIT8(KSomeLIT8Text,"qwerty");
相当于:const static TLitC8<7> KSomeLIT8Text;

五、使用类TLitC的重载操作符

一共有4个重载操作符,返回类型分别是:

(1)一个TRefByValue<class T>类型的引用
示例程序
...
TBuf<256> x;
...
_LIT(KTxtFormat,"There are %d cm in a metre");
x.Format(KTxtFormat,100); //编译器自动调用重载操作符
...

(2)指向常量描述符的常量引用
...
_LIT(KSomeData,"Some data");
...
TPtrC x(KSomeData);

(3)指向常量描述符的指针
class CX...
 {
 void Foo(const TDesC* aDesC);
 };

...
_LIT(KLiteral,"some text");
...
CX* anx;
...
anx->Foo(&KLiteral);
...

(4)一个常量描述符的引用
...
_LIT(KKeywordSelect,"select");
if (KKeywordSelect().CompareF(token)<0)
...

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值