商务智能S系统开发教程_第1页
商务智能S系统开发教程_第2页
商务智能S系统开发教程_第3页
商务智能S系统开发教程_第4页
商务智能S系统开发教程_第5页
已阅读5页,还剩17页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

(商务智能)S系统开发教程第二章:数据类型与语法作者:谢兴enigma19971@hotmail.转载需注明出处Symbian系统已经提供了一套已经定义好的内置的数据类型。为了保证你的代码是编译器无关的,应当使用下面symbian系统提供的数据类型,而不要使用原生数据类型(nativetypes,这里指标准C中的int,char1.基本类型TIntX和TUintX(其中X=8,16和32)分别用来表示8位,16位和32位的有符号和无符号的整数。一般情况下,使用TInt和TUint就可以了,除非是在考虑代码优化或兼容性的时候,才会用到TInt8,TInt16这样的类型。TInt或TUint类型分别对应有符号和无符号的整数。TInt64.在版本8.0之前,Symbian系统中不支持6432位的值来实现64位的整数,在8.0版本之后,TInt64和TUInt64才被定义为longlong类型,真正使用64位的内置数据类型。TReal32和TReal64(TReal相当于TReal64)一般应尽量避免使用浮点数的运算。TTextX(其中X=8或16)ASCII码字符,而宽字符是指unicode字符集的字符)TAny*TAny*TAny相当于void,TAny*相当于TAny*。但是,在某些场合下,void标示‘空,如:voidhello(void);这时,不要将它改写为:TAnyhello(TAny);TBool标示布尔类型。SymbianETrue(=1)和EFalse(=0),分别表示真和假。注意:在Symbian系统中,TBool被定义为int,而ETrue和EFalse被定义为enum,所以,如果一个函数的返回值为TBool,不要用如下的代码来比较函数的返回值:TBoolisLarger(TInta,TIntb){return(a>b)?ETrue:EFalse;}if(isLarger(4,3)==ETrue){...}//错误,编译不过。if(isLarger(4,3)){...}//正确2类和对象2.1Symbian系统中的命名习惯:在Symbiani开头,方法的参数以小写字母a开头,例如:classPernon{public:TIntiAge;voidSetAge(TIntaAge){iAge=aAge};}在symbianclass有的在堆(heap)上创建,有的在栈(stack)上创建,特别的是,类的实例(instance)classtype)了容易区分型别,Symbian系统使用了一个简单的命名规则:类名以大写字母开头(T,C,R或M熟悉这个类,但类的命名规则可以帮助他弄清你的意图------如何用安全的方式初始化、使用和销毁一个类的对象(object下面,我主要讨论不同型别的主要特性。T类T类的行为类似于C++T作前缀代表置类型一样,它们没有析构方法(destructorT类不能包含具有析构方T类的成员变量只能是内置类型的数据或者是其它的T类T用”关系,而不是“拥有”关系(也就是说,这个T类对象并不负责对成员的创建和销毁的T类没有析构方法。正是由于没有析构方法,T类的对象可以在栈上创建,当程序流程退出函数或产生leave(一种代码异常)的时候,系统自动清除它。即使T类有一个析构方法,在发生异常(在Symbian系统中,异常被称为leave)时Symbian系统也不会调用它,因为leave没有模仿标准C++的抛出异常的做法。T类的对象也可以在堆上创建。但是,应当在调用有可能发生异常的代码之前,将这个对象放入到清除栈(cleanupStack清除栈(cleanupStack)会释放这个对象。C类这种类都是从CBase//.hfileclassCStudent:publicCBase{public:CStudent(){RDebug::Print(_L("iamastudent"));};~CStudent(){RDebug::Print(_L("please,don'tkillme!"));}voidSampleFunction(){};private:TIntiCode;TIntiScore;};CBaseCBase指针来删除它的子类。代码如下所示:CBase*pStu=newCStudent();deletepStu;结果:iamastudentplease,don'tkillme!其次,CBasenew始化为00您不必在构造方法中去做这件事情。但是,在栈上创建对象时,情况并非这样,因为这时没有用到newC类的对象一定要在堆上创建。很明显,当一个堆上的C类对象不再被需要时,我们需要消耗它。一个C类的对象可能以两在类的析构方法中调用delete(leavecleanupstack存泄露。CBase=CleaveCloneL()或CopyL()。如果您提供的这个类是从CBase派生的,您私有的。R类前缀“R”Resource,handle和C类不同,Symbian系统中不存在一个对应的RBaseR类应当有一个构造方法来将它的资源句柄置为0,表明还没有资源和这个新建的对象关联在一起。但是,不要在构造方法中初始化资源句柄,因为这样有可能使构造方法产生异常。R类中常常有类如Open(),Create()或Initialize()回错误代码或是产生异常。R类通常也有对应的CloseReset()置句柄的值------表明没有资源和该对象关联。使用R类时,一个常见的错误是忘记调用它的Close()方法(当然,该方法也可以是其它名字,但它经常被命名为Close个析构方法释放资源,这会引起资源的泄露。R类通常都很小,除了资源句柄没有其它的成员变量。因为不需要。它通常也没有析构Close()R类都是作为类的成员变量或局部变量存在的。只有少数情况下,在堆上创建。您必须确保,当程序发后异常的时候,资源能被正确地释放------通常是使用资源栈。如果一个R变量本身也要被释放。typicallybyusingtwopushcalls:CleanupClosePushL(),orasimilarfunction,toensurethattheresourceiscleanedup,andastandardCleanupStack::PushL(TAny*)whichsimplycallsUser::Free()ontheheapcell.R类的成员变量通常都很简单,所以一般不需要深拷贝(bitwisecopyR类的拷贝可能会引起混乱(想象一下:如果两个对象同时在一个资源句柄上调用Close()方法,或两个R不定义)一个私有的构造方法和赋值操作。M类M是单词Mixin的首字母。SymbianM类是一个抽象类,它的作用相当于java中的接口(interfaceSymbian系统中,M类常被用来定义回调接口或者是观察者(observer)类。M类也可以被其它类继承。下面我们给出两个例子。classMAnimal{public:virtualvoidEatL()=0;};classMDomesticAnimal:publicMAnimal{public:virtualvoidNameL()=0;};classCCat:publicCBase,publicMDomesticAnimal{public:virtualvoidEatL(){};//从MAnimal,经过MDomesticAnimal继承virtualvoidNameL(){};//从MDomesticAnimal继承//Otherfunctionsomittedforclarity};上面的例子演示了一个从CBase类和一个M类派生的具体类。而类MDomesticAnimal又是从MAnimal派生的。象接口一样,由于不能被实例化,M类只能有虚(virtual)函数,不能CBase派生的。在定义完类以后,然后可以用使用它。代码如下:CCat*cat1=newCCat;deletecat1;//正确然下面的代码却是错误的。MAnimal*cat2=newCCat;deletecat1;//错误当用MdeleteM类必须提供一个虚拟的析构方法,否则会出现系统异常(paniccode42MAnimal的代码改写,则上面代码没有问题。classMAnimal{public:virtualvoidEatL()=0;virtual~MAnimal();//增加一个虚的析构方法。};3描述符(descriptor)在Symbian系统中,字符串被称为“描述符(descriptor在描述符中保存了它所表示的字符串的长度和它的底层的内存布局的信息。描述符比标准C中的字符数组和字符指针要复杂,您可能需要多花些时间来学习和掌握它的用法。关键是,己的长度和内存布局的信息。现在,让我们来深入了解描述符的设计思想。在Symbian系统中,描述符是相当让人迷惑的,因为它的种类繁多。不同种类的描述符C++中的string,java语言中的string类或MFC中的CString,因为程序员必须自己管理底层的内存分配和清除工作。它们具有防治内存溢出的机制,并且不依赖NULL终结符号来决定字符串的长度,从这方而来讲,它也不同于C语言中的字符串。现在我们来讨论:什么是描述符?它们是如何工作的?在探讨这些不同的描述符之前,先让我们需要弄清楚一个基本的概念:什么是字符串数据的“宽度”?这个长度指的是单个字符是8bit的,还是16bit的宽度。在早期的版本中,字符的宽度都是8bit的,后来为了支持Unicode字符集,从第5版起,Symbian系统将16bit的字符作为标准。Symbian系统现在Copy()和Size()8TPtr8,就意味着它表示是的8bit的窄字符,而以16结尾的描述符类(例如:TPtr16)则操作16bit的宽字符。neutralTPtr,在Symbian系统第516bit于TInt,TInt16或TInt32之间的关系,这一点应当是比较易于理解的。平常写代码,大多情况下,仅仅使用UINT类型,而较少考虑使用UINT16,UINT32另外一个问题是:描述符和字面量(literal)的区别。所谓字面量是指在编码的时候就已经确定的量,例如,标准C中的char*p="Helloworld";其中的"Helloworld"Symbian点我们在后面再介绍。有了这样的一些认识,Symbian系统中描述符类型有两大种类:不可修改(non-modifiable)的描述符和可修改(modifiable)的描述符。3.1不可修改(non-modifiable)的描述符在Symbian系统中,所有的描述符都继承自TDesC,在前面我们已经讨论了类名前缀T所CC是单词Constant的首字Length()方法返回了描述符的长度,因为,每个描述符对象在内存中的布局都是同样的,用432个bit中的28个bit4bit留作它用,所以描述符能表示的最大的长度为228字节,256MBLength法的不同,子类访问数据的方式也不一样,Symbian系统不要求它的子类通过虚函数的方式来实现自己的访问数据的方法。不用虚函数重写的原因是因为,虚函数会给每个被派生的描述符对象增加4节字的额外负担,c++用这4个字节来存放指向虚函数表的指针。我们前面度的4个字节中,28bit用来表示长度,剩下的4bit用来表示描述符的类型。目前,symbian系统中有5种派生的描述符类型,4bit限制了描述符的种类最多只能有16种,但这已经足够TDesC的PtrPtr()方法检查这4个bitTDesC基类清楚它的子类的内存布局,并在Ptr()方法中使用硬编码的方法。后面,为了表述上的方便,我们也把这种不可修改的描述符也称为常量描述符(constantdescriptor)总结:不可修改的描述符类TDesC是所有的非字面量描述符的基类,它提供了确定描述符长度和访问数据的方法,另外,它实现了所有的您想用来处理常量字符串的操作。3.2可修改(modifiable)的描述符所有的可修改的描述符都从TDes基类派生,而TDes本身又是从TDesC派生的。TDes有一个额外的成员变量用来存放为该描述符分配数据的最大长度。MaxLength()方法返回了这个最大的长度。像TDesC中的Length()方法一样,MaxLength()方法也不被TDes的子类继承。TDes类提供了一系列的方法,复制赋值的方法。这些方法都不负责分配内存,假如它们超过了描述符的数据长度,例如,用Append断言(assertion)来确保描述符的最大长度不会被超出。如果发生内存溢出,将会产生一个panic(关于panic存陷阱。protecedTDesC或TDes如前面所说,这个地方是比较让人迷惑的,因为描述符存在大量的派生类。前面,我们已TDes8,TDes16和TDes,分别对应窄字个字符串存储在内存中的基它位置。与指针描述符不同,缓存区描述符本身持有字符数据,也就是说字符数据本身构成了描述符的一部分。总TDes是所有的可修改的描述符的基类,并且它自己也是从TDesC派生的。它有一个能返回最大的内存容量的方法和一系列的用来修改字符串数据的方法。3.3指针描述符(pointerdescriptor)指针描述符可分为两种:TPtrC和TPtr(我们前面说过,每种类型的描述符,按照字符宽度,都可以分为三个版本,例如:窄字符版本TPtrC8,宽字窄版本TPtrC16和中立的版本TPtrCROM符(HBufC,下面将要讲解)来操作内存的分配和销毁;如果指针描述符所指向的字符串是的,但有时候,它们也可以在堆上使用,例如:作为一个CBase派生类的成员变量的时候。在不可修改的描述符(TPtrC)中,指向数据的指针存放在长度的后面,因此,指针描述符的总长度为2个字(word总长度为3个字。下图比较了TPtr和TPtrC内存布局.TPtriLength(1iMaxLengthiPtrHelloworld!TPtrCiLength(1iPtrTPtrCTPtrC相当于C语言中的constchar*TDesC中继承的操作都是可访问的。TPtrC定义了一系列的构造方法,使得它能从其它的描述符、指向内存的指针或以0结尾的C语言字符串构造。//字面量描述符将在后面介绍_LIT(KLiteralDes,"Sixtyzipperswerequicklypickedfromthewovenjutebag");TPtrCpangramPtr(KLiteralDes);//从字面量描述符构造TPtrCcopyPtr(pangramPtr);//从其它的描述符构造TBufC<100>constBuffer(KLiteralDes);//常量缓存区描述符,后面介绍TPtrCptr(constBuffer);//ConstructedfromaTBufC//TText8isasingle(8-bit)character,equivalenttounsignedcharconstTText8*cString=(TText8*)"Waltz,badnymph,forquickjigsvex";//从以0结尾的字符串构造TPtrC8anotherPtr(cString);TUint8*memoryLocation;//PointerintomemoryinitializedelsewhereTIntlength;//Lengthofmemorytoberepresented...TPtrC8memPtr(memoryLocation,length);//从一个指针构造。这个指针本身可以改变成指向其他的字符串数据(通过Set)改变您的TPtrCTPtrC声明为constSet()方法更改TPtrC所指向的数据时,编译器会产生警告。//字面量描述符_LIT(KLiteralDes1,"Sixtyzipperswerequicklypickedfromthewovenjutebag");_LIT(KLiteralDes2,"Waltz,badnymph,forquickjigsvex");TPtrCalpha(KLiteralDes1);TPtrCbeta(KLiteralDes2);alpha.Set(KLiteralDes2);//alphapointstothedatainKLiteralDes2beta.Set(KLiteralDes1);//betapointstothedatainKLiteralDes1constTPtrCgamma(beta);//Pointstothedatainbeta,KLiteralDes1gamma.Set(alpha);//Generatesawarning,butpointstoalpha这里应当加一些示范代码TPtrTPtrTDesC和TDes所提供的所有的操作都适用于TPtr针构造,并设置适当的长度值和最大长度值。的。一个TPtrDes()方法,这个方法返回一个如下所示的TPtr对象:_LIT(KLiteralDes1,"Jackdawslovemybigsphinxofquartz");TBufC<60>buf(KLiteralDes1);//TBufCaredescribedlaterTPtrptr(buf.Des());//Copyconstruction;canmodifythedatainbufTIntlength=ptr.Length();//Length=37TIntmaxLength=ptr.MaxLength();//Maximumlength=60,asforbufTUint8*memoryLocation;//Validpointerintomemory...TIntlen=12;//LengthofdatatoberepresentedTIntmaxLen=32;//Maximumlengthtoberepresented//ConstructapointerdescriptorfromapointerintomemoryTPtr8memPtr(memoryLocation,maxLen);//length=0,maxlength=32TPtr8memPtr2(memoryLocation,len,maxLen);//length=12,max=32另外,TPtr提供了赋值运算符=(),用来拷贝数据到指针所指向的内存(数据源可以是0TPtrCTPtr也定义了一个Set来改变描述符所指向的数据。_LIT(KLiteralDes1,"Jackdawslovemybigsphinxofquartz");TBufC<60>buf(KLiteralDes1);//TBufCaredescribedlaterTPtrptr(buf.Des());//PointstothecontentsofbufTUint16*memoryLocation;//Validpointerintomemory...TIntmaxLen=40;//MaximumlengthtoberepresentedTPtrmemPtr(memoryLocation,maxLen);//length=12,maxlength=40//CopyandreplacememPtr=ptr;//memPtrdataisKLiteralDes1(37bytes),maxLength=40_LIT(KLiteralDes2,"Thequickbrownfoxjumpsoverthelazydog");TBufC<100>buf2(KLiteralDes2);//TBufCaredescribedlaterTPtrptr2(buf2.Des());//Pointstothedatainbuf//Replacewhatptrpointstoptr.Set(ptr2);//ptrpointstocontentsofbuf2,maxlength=100memPtr=ptr2;//AttempttoupdatememPtrwhichpanicsbecausethe//contentsofptr2(43bytes)exceedsmaxlengthofmemPtr(40bytes)您一定不要混淆了Set=()改它的最大长度值。3.5基于栈(stack-based)的缓冲区描述符基于缓冲区的描述符也可以分为可修改的TBuf和不可修改TBufC的两种类型。对这种描述符来讲,字符串数据本身就是描述符的一部分。下图给出了描述符的内存布局:这两种描述符通常用来存储定长的或相对较小的字符串,常用来存放长度小于256个字符的文件名。类似于C语言中的char[],但是,它们具有检查内存溢出的功能。TBufC<n>TBufC<n>从TBufCBase类派生,尖括号<>内的数字表示分配给该描述符的数据区的大小。它定义了一些构造方法,允许从其它的描述符或以0结尾的字符串构造。也允许创建一个空的描述符,然后再填充。0是何种情况,新数据的长度都不能超过长度n_LIT(KPalindrome,"Satan,oscillatemymetallicsonatas");TBufC<50>buf1(KPalindrome);//ConstructedfromliteraldescriptorTBufC<50>buf2(buf1);//Constructedfrombuf1//ConstructedfromaNULL-terminatedCstringTBufC<30>buf3((TText*)"Neveroddoreven");TBufC<50>buf4;//Constructedempty,length=0//Copyandreplacebuf4=buf1;//buf4containsdatacopiedfrombuf1,lengthmodifiedbuf1=buf3;//buf1containsdatacopiedfrombuf3,lengthmodifiedbuf3=buf2;//Panic!Maxlengthofbuf3isinsufficientforbuf2dataDes它为缓存区中的数据返回一个可修改的指针描述符(TPtr符中的iLength的值会跟着改变,但要记住,缓存区描述符的长度值只可能减小,而是不可能增大的,因为,描述符类是不提供内存管理管理功能的。_LIT8(KPalindrome,"Satan,oscillatemymetallicsonatas");TBufC8<40>buf(KPalindrome);//ConstructedfromliteraldescriptorTPtr8ptr(buf.Des());//dataisthestringinbuf,maxlength=40//Illustratestheuseofptrtocopyandreplacecontentsofbufptr=(TText8*)"DoGeeseseeGod?";ASSERT(ptr.Length()==buf.Length());_LIT8(KPalindrome2,"Arewenotdrawnonward,wefew,drawnonwardtonewera?");ptr=KPalindrome2;//Panic!KPalindrome2exceedsmaxlengthofptr(=40)TBuf<n>这也是一个模板类,它是一个可修改的缓冲区描述符类,后面的<n>表示缓冲区大小。TBuf从TBufBase类派生,而TBufBase是从TDesTDes和TDesC类所有的TBufC<n>一样,TBuf<n>n保数据长度不要超过缓存区的最大长度。如果需要使用动态分配的内存,您可以使用基于堆的描述符,这个我们在后面要讲到。使用动态数组的额外开销是很高的。_LIT(KPalindrome,"Satan,oscillatemymetallicsonatas");TBuf<40>buf1(KPalindrome);//ConstructedfromliteraldescriptorTBuf<40>buf2(buf1);//ConstructedfromconstantbufferdescriptorTBuf8<40>buf3((TText8*)"DoGeeseseeGod?");//fromCstringTBuf<40>buf4;//Constructedempty,length=0,maximumlength=40//Illustratecopyandreplacebuf4=buf2;//buf2copiedintobuf4,updatinglengthandmaxlengthbuf3=(TText8*)"Murderforajarofredrum";//updatedfromCstring3.6基于堆的(Heap-Based)缓冲区描述符的,这时,它的作用相当于C语言中的malloc。HBufCHBufC的类名以“H”Symbian系统中惯用的命名习惯。这的确是一个特例,“H”HeapHBufCNewL()HBufC表示这个表述符是不可修改的。对该类的操作几乎和TBufC<n>区中的内容被替换掉;同样,新内容的长度不能超过缓存区的大小,否则会引起系统异常;通过调用Des()TPtr来更改缓冲区中的内容。_LIT(KPalindrome,"DoGeeseseeGod?");TBufC<20>stackBuf(KPalindrome);//Allocatesanemptyheapdescriptorofmaxlength20HBufC*heapBuf=HBufC::NewLC(20);TIntlength=heapBuf->Length();//Currentlength=0TPtrptr(heapBuf->Des());//Modificationoftheheapdescriptorptr=stackBuf;//CopiesstackBufcontentsintoheapBuflength=heapBuf->Length();//length=17HBufC*heapBuf2=stackBuf.AllocLC();//Fromstackbufferlength=heapBuf2->Length();//length=17_LIT(KPalindrome2,"Palindrome");*heapBuf2=KPalindrome2;//CopyandreplacedatainheapBuf2length=heapBuf2->Length();//length=10CleanupStack::PopAndDestroy(2,heapBuf);的大小。在修改缓存区的内容之前,您要确保缓存区的内存是足够的。为了帮您简化这些操作,HBufC提供的一套ReAllocL()方法,它可以用来扩展堆的缓存区(这个操作有可能会IftheHBufC*isstoredonthecleanupstack,movingthepointerasaresultofmemoryreallocationcancausesigni.cantproblemseitherintheeventofaleaveorifthecleanupstack’sPopAndDestroy()functionisusedtodestroythememory.如果您在HBufC上调用Des()方法来获取了TPtr,在经过重新分配内存后,TPtr中的成员变量iPtr有可能变成无效的。因此,为了确保安全,在重新分配内存后,应该再次调用Des()来创建一个新的TPtr对象。注:出于性能上的考虑,Symbian系统并没有提供可修改的堆描述符HBuf。总Symbian系统中总共有5种类型的描述符,TPtrC,PTtr,TBufC<n>,TBuf<n>和HBufC。下面的图示表明了它们的继承关系。3.7字面量描述符(LiteralDescriptors)C语言中的staticchar[]系列的宏来创建的,这些宏可在头文件e32def.H中找到#define_L8(a)(TPtrC8((constTText8*)(a)))#define_S8(a)((constTText8*)a)#define_LIT8(name,s)conststaticTLitC8<sizeof(s)>name={sizeof(s)-1,s}#define_L16(a)(TPtrC16((constTText16*)L##a))#define_S16(a)((constTText16*)L##a)#define_LIT16(name,s)conststaticTLitC16<sizeof(L##s)/2>name={sizeof(L##s)/2-1,L##s}首先,我们来看_LIT,这是最有效率也是被使用得最多的一个。这个宏的用法如下:_LIT(KMyLiteralDescriptor,"Thequickbrownfoxjumpsoverthelazydog");后面KMyLiteralDescriptor就可以作为一个常量来使用,例如可以将它写到文件或显示给用户。_LIT宏构建了一个名为KMyLiteralDescriptor的TLitC16Thequickbrownfoxjumpsoverthelazydog可以找到这个值,因为它是被写到文件中的。如您所料,_LIT8和_LIT16的用法相似。因为描述符的宽度为16bitC符串的长度除以2。TLitC16__TText被定义为宽的,16bit的字符。TLitC8也有类似的定义。template<TIntS>classTLitC16{public:inlineconstTDesC16*operator&()const;inlineoperatorconstTDesC16&()const;inlineconstTDesC16&operator()()const;...//Omittedforclaritypublic:TUintiTypeLength;__TTextiBuf[__Align16(S)];};template<TIntS>inlineconstTDesC16*TLitC16<S>::operator&()const{returnREINTERPRET_CAST(constTDesC16*,this);}template<TIntS>inlineconstTDesC16&TLitC16<S>::operator()()const{return*operator&();}template<TIntS>inlineTLitC16<S>::operatorconstTDesC16&()const{return*operator&();}从上面的定义中可以看到,TLitC16(和TLitC8)并不从TDesC8或TDesC16与TBufC8或TBufC16TLitC16(和TLitC8)可以用在任何可以使用TDesC的地方。您也可以用如下的方法从一个字面量构造一个指针描述符:TPtrC8thePtr(KMyLiteralDescriptor);size_LIT返回相应的TLitC对象的尺寸大小,这个尺寸相当于描述符内容的尺寸加上额外的8个byte(用来存放长度值的4字节和表示结束符的NULL须要将这额外的8个字节考虑进去。//定义一个包含44字符的字面量_LIT8(KExampleLit8,"Thequickbrownfoxjumpedoverthelazydog");TIntsize=sizeof(KExampleLit8);//52bytes(contents+8bytes)TBufC8<(sizeof(KExampleLit8)-8)>theStackBuffer(KExampleLit8);符中。为了得到正确的长度,您可以用公共(public)的成员变量iTypeLength,或者,也调用TDes::AllocL()方法,返回一个HBufC*,代码如下:TIntdescriptorLength=KExampleLit8.iTypeLength;//44bytes//Formastackbufferdescriptoraroundtheliteral//CreateaheapbuffercopyingthecontentsoftheliteralHBufC8*theHeapBuffer=KExampleLit8().AllocL();//对宽字符字面量的操作类似_LIT16(KExampleLit16,"Thequickbrownfoxjumpedoverthelazydog");size=sizeof(KExampleLit16);//96bytes(contentsinbytes+8bytes)descriptorLength=KExampleLit16.iTypeLength;//44bytes(contents)用_L和_LIT生成的字面量,它们的内存布局是有差异的,如下图所示:现在我们简单地看看_L和_S宏,这两个宏已经过时,但在测试代码中还经常用到。RDebug::Print(_L("Helloworld!"));这个代码的作用相当于:_LIT(KLit,"Helloworld!");RDebug::Print(KLit);从上面的代码可以看到,使用_L的好处在于,您可以直接使用它,而无需在使用之前,world!被作为一个基本的以0结尾的字符串写到二进制文件中,它前面没有长度值(这不同于_LIT产生的字符串)。由于没有长度值,字面量的内存布局不同于描述符,并且当代码运行的时候,_L的第个实例都会产生一个临时的TPtrC,这个TPtrC的指针指向字面量的第一个字节在ROM会使得二进制程序的体积增大。如果仅从存储方式上看,_S宏和_L是相同的,但有一点不同------它不产生临时的TPtrC0用_S宏。的方法和在使用描述符时一些常见的问题。3.8描述符作参数和返回类型TBuf您的客户也改变他们的代码。这样的改动是非常不理想的,因为它破坏了代码的兼容性。5返回值。为了有效率,描述符参数应当使用引用传递的方式,要么是constTDesC&或者是TDes&。例如,类RFile定义了read()和write()方法IMPORT_CTIntWrite(constTDesC8&aDes);IMPORT_CTIntRead(TDes8&aDes)const;8bit外传递一个参数用来表示返回的数据长度。当写一个函数的时候,如果参数是可修改的描述符,实际上您不必考虑它是否有足够生系统异常。当然,您也可能不希望在描述符数据区过短的情况下,描述符的方法会发生系统异常。的描述符。HBufC*CPoem::DoGetLineL(TIntaLineNumber){//Codeomittedforclarity.Allocatesandreturnsaheapbuffer//containingthetextofaLineNumber(leavesifaLineNumberis//outofrange)}voidCPoem::GetLineL(TIntaLineNumber,TDes&aDes){HBufC*line=DoGetLineL(aLineNumber);CleanupStack::PushL(line);//Isthedescriptorlargeenough(4bytesormore)toreturnan//integerrepresentingthelengthofdatarequired?if(aDes.MaxLength()<line->Length()){if(aDes.MaxLength()>=sizeof(TInt)){//Writesthelengthrequired(TPckgisdescribedlater)TPckg<TInt>length(line->Length());aDes.Copy(length);}//Leave&indicatethatthecurrentlengthistooshortUser::Leave(KErrOverflow);//LeavesaredescribedinChapter2}else{aDes.Copy(*line);CleanupStack::PopAndDestroy(line);}}另一个方案是,在函数中分配堆缓冲区,把它返还给调用者,由调用者负责销毁它。3.9常用的方法Ptr()基类TDesC实现了Ptr()方法,用来访问描述符的数据,该方法返回一个指向字符数组首地址的指针。您可以通过这个指针来直接操作字符串数据。代码如下所示:Size()和Length()TDesC实现了Size()andLength()方法,前者返回描述符所占有的字节数,而后者返回8bit,而对16bit的描述来说,Size()返回的数值是Length()的两倍。MaxLength()可修改的描述符TDes实现的这个方法返回描述符的最大长度。SetLength()和SetMax()Zero()和FillZ()前者将描述符的长度设置为00填充描述符的内容,可用Fill()方法。这个方案类似于C语言中的memset()函数。Copy()TDes实现了一系列的重的Copy()方法,下面是其中的两个:IMPORT_CvoidCopy(constTDesC8&aDes);IMPORT_CvoidCopy(constTDesC16&aDes);如可源描述符的长度超过目标描述符的最大长度,将会引发一个系统异常。3.10使用HBufC堆描述符我们已经讨论过描述符的一些特性,现在来关注一下使用描述符时经常容易范的错误。首先,我们将创建和使用堆描述符HBufC。前面提到过,在已有的描述符上调用Alloc()或AllocL()方法,可以产生一个新的HBufC。这里是一个例子:voidCSampleClass::UnnecessaryCodeL(constTDesC&aDes){iHeapBuffer=HBufC::NewL(aDes.Length());TPtrptr(iHeapBuffer->Des());ptr.Copy(aDes);...//以上代码完全可以被下面的代替,下面代码更有效率。iHeapBuffer=aDes.AllocL();}Anothermonwaytointroduceplexityoccursintheoppositedirection,thatis,thegenerationofTDesC&fromaheapdescriptor.当从一个堆描述符产生一个TDesC&复杂性。代码如下所示:constTDesC&CSampleClass::MoreAccidentalplexity(){return(iHeapBuffer->Des());//以上代码完全可以写成return(*iHeapBuffer);//这样更简洁高效}另外一个比较微妙问题是,当您分配一个HBufC以后,然后在它上面调用Des返回一个TPtr对象。HBufC*buf=HBufC::NewL(9);TPtrp=buf->Des();可是,HBufCword的信息------因为HBufC是不可修改的(non-modifiable)TPtr需要这个最大长度的信息,这时问题来了,您从哪里得到这个最大长度呢?答案在于:当您调用Des()的时候,系统用HBufC的最大长度来设置TPtr的最大长度(iMaxLength在这个例子中,buf的最大长度是多少呢?它是9可能并不是您所期望的值(在这个例子中为9)。这是由于您并没有指定一个字对齐(word-aligned)的最大长度,所以最后的实际的长度可能比您所指定的长度要大一些(但我们不能确定这个值到底是多少)。_LIT(KPanic,"TestPointer");constTIntKBufferLength=9;voidTest

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论