Wiley.Symbian.OS.C.plus.plus.for.Mobile.Phones.Aug.2007 (779890), страница 22
Текст из файла (страница 22)
This removes the need for the descriptordata to be delimited with a ‘\0’ character as it is in C, a consequenceof which is that it allows binary data to be stored as well as string data.It also means that data beyond the bounds of the descriptor cannot beaccessed by mistake.STACK DESCRIPTORS93The maximum length field is used to store the maximum capacity ofthe data which can be held. This is used to prevent memory overruns.When an attempt is made to write or access data beyond a descriptor’sboundary, a User-11 panic is generated.5.3 LiteralsWe look at literals first because they are used in most of the code exampleswithin this chapter.A program binary consists of the compiled and linked DLLs and EXEsthat make up a program.
A literal string is one which is included in theprogram binary. As a program binary is execute either directly from ROMor from read-only RAM, any literals it contains are also read-only.In standard C, a string literal would be included in the program binaryby declaring the variable as a static constant array and initializing it withcharacter data:static const char KTxtHelloWorld[] = "Hello World!";In Symbian OS, literal strings are included in the program binary usingthe TLitC class, however you never actually use this class directly,instead you use it indirectly via the macro _LIT as follows:_LIT(KTxtHelloWorld, "Hello World!");This adds the string literal ‘Hello World!’ of type TLitC to the programbinary and associates the symbol KTxtHelloWorld with it so that it canbe referenced.The binary layout of TLitC is designed to be identical to a TBufC(Figure 5.2), which allows a TLitC to be treated as a descriptor.5.4 Stack DescriptorsThere are two stack descriptors: TBuf and TBufC can be used in a similarway to that in which a char [] or const char [] array would be usedin C.
The descriptor data is stored within the descriptor objects as partof their member data. As their name suggests, they are typically declaredon the stack (they can be allocated on the heap, but read Section 5.11before doing this).There are a number of ways they can be created; here they areconstructed from a literal:94DESCRIPTORS_LIT(KTxtHello, "Hello");TBuf<11> buf(KTxtHello);TBufC<5> bufC(KTxtHello);// equivalent to char buf[12] 2// equivalent to const char bufC[6]The classes are a templated array and take an integer value that definesthe maximum length of data that the descriptor can hold. In this case thebuf variable can store a maximum of 11 items and the bufC variable amaximum of five.
The contents of the KTxtHello literal are physicallycopied into each descriptor’s array space.In both these examples, there is sufficient space for the data to becopied, but if KTxtHello had instead contained ‘Hello!’ and thus hadbeen of length six, then there would be a panic during the constructionof the bufC variable.The TBufC<5> object layout is shown in Figure 5.3. The templateparameter value defines the length of the data area available; the lengthof the data copied is also five; it could have been less than five, butdefinitely not more than five.Type 0Length 5HeFigure 5.3lloTBufC<5> layoutCompare this with the layout for the TBuf<11> object in Figure 5.4.The length is still five but the maximum length is eleven and there is roomto insert, or append, another six items.MaxType 3 Length length511HelFigure 5.4loTBuf<11> layoutOnce you have a TBuf object you can use a variety of methods tomanipulate its content.
The following code illustrates appending text tothe buf variable created above:_LIT(KTxtSpace, " ");_LIT(KTxtWorld, "World");buf.Append(KTxtSpace); // buf contains "Hello " and is 6 longbuf.Append(KTxtWorld); // buf contains "Hello World" and is 11bufC.Append(KTxtSpace); // Error: Append() is not a TbufC method2Notice how, in the equivalent C code, the length of the array is 1 more than in thecorresponding descriptor code. This is because C strings need to store the NULL terminator.POINTER DESCRIPTORS95It is not possible to Append() data to the bufC variable becauseTBufC objects cannot be directly manipulated (however, there is anindirect way which is described in Section 5.5).Once the buf variable contains the data ‘Hello World’, then bothits length and maximum length data members are 11 and thus it is notpossible to append any more data to it:_LIT(KTxtExclamation, "!");buf.Append(KTxtExclamation);// buf’s length cannot exceed 11// so the code will panicSee Section 5.12 for a full list of methods for manipulating and accessing descriptor data.As already mentioned, stack descriptors are usually declared on thestack; often they are embedded in other classes.
Allocating them directlyon the heap is possible though not recommended for the reasons outlinedin Section 5.11. A common situation where a TBuf is used is when youneed to construct a descriptor, use it, and then discard it all within onemethod and you do not want to bother with memory allocation. TBufCis usually embedded in other objects.3A TBufC uses four bytes less RAM than a TBuf (as it doesn’t store amaximum length), therefore using a TBufC saves four bytes of storageper object. Even if you need to modify the contents, you can still use aTBufC as it can be modified via its Des() method; however a call toDes() takes up space in ROM.If you are using only a small number of stack descriptors then therecommendation is to simply use whichever is easiest to use to suit yourpurposes.
If you are using many of them then decide if it is more desirableto save ROM space or RAM space.5.5 Pointer DescriptorsWhile TBuf and TBufC are implemented as templated arrays and containa physical copy of data, TPtr and TPtrC instead contain a pointer todata and can be used in similar circumstances to those in which char*or const char* are used in C.A pointer descriptor object can either go onto the program stack orit can be a data member of some class, but the data pointed to can beanywhere that is addressable by your code.
If a pointer descriptor points3Some people are confused about whether a TBuf or TBufC declared as a data memberinside a class is on the heap or the stack – if they are data members of a CBase-derived classthen they are allocated on the heap because all CBase-derived classes are, by definition,allocated on the heap.96DESCRIPTORSto data allocated in the heap, it is not responsible for the allocation orde-allocation of that memory.
You must of course ensure that any datathe pointer descriptor is pointing to exists for the duration of the pointerdescriptor.TPtrC DescriptorsA TPtrC is similar to a const char* in C. It can be set to point tomany things: descriptor data, portions of descriptor data, raw memory,or a literal string located in ROM. Here are some examples (the first ofwhich is illustrated in Figure 5.5):// 1 Construction of a TPtrC from a literal_LIT(KTxtHello, "Hello");TPtrC ptr(KTxtHello); // ptr points to "Hello" in the program binary// 2 Setting a TPtrC to point to data in a stack descriptor_LIT(KTxtWorld, "World");TBufC<5> buf(KTxtWorld);ptr.Set(buf);// ptr points to "World" in the buf descriptor variable// 3 TPtrC set to point to raw data held in a C-style arrayconst TText array[6] = L"Hello";ptr.Set(array, 5);// ptr points to "Hello" in the array variable// 4 TPtrC set to point to a portion of data held in a// descriptorptr.Set(buf.Mid(1,2)); // ptr points to "or" in the buf// descriptor variableCode example 3 above shows how TPtrC is useful if you have somedata that is not in the form of a descriptor, but you have to pass that datato a method expecting a descriptor argument – after being set, the ptrvariable can be passed directly to the method.Type 1 Length 50x02003D48HelloFigure 5.5 TPtrC layoutType 2 TPtr DescriptorsTPtr is a modifiable pointer descriptor class allowing access to, andmodification of, the character or binary data it points to.
There are twoflavors of TPtr: type 2 points to data (which may or may not be heldwithin a descriptor) and type 4 points to a descriptor.POINTER DESCRIPTORS97All TPtrs are type 2 unless they are created using the HBufC::Des()or TBufC::Des() methods. In practice, type 2 TPtrs are not usedparticularly often and there are not many good real-world examples oftheir usage within the Symbian OS code base. An example usage wouldbe if you wanted to modify the contents of raw memory or data as adescriptor. The following code shows how a type 2 TPtr can be usedto point to non-descriptor data and then write to that data as if it werea descriptor:TText cStyleArray[] = L"Hello"; 4// Creates a pointer to the array of data.
The 2nd parameter is// the length of the data pointed to and the 3rd parameter is// the maximum length of the data pointed to.// sizeof(cStyleArray) returns 12 which is the number of bytes,// however the conceptual length of the data is 6, hence the// division by 2.TPtr ptrToRawData(cStyleArray, sizeof(cStyleArray)/2,sizeof(cStyleArray)/2);// copy "World" into the cStyleArray memory location_LIT(KTxtWorld, "World");ptrToRawData = KTxtWorld; // cStyleArray now contains "World"// TPtrs provide safety when writing to raw memory as an attempt// to write beyond the end of the data storage area results in// a panicptrToRawData += KTxtWorld;// this will panic!In the above example, the TPtr is created using the constructorTPtr::TPtr(TUint16 *aBuf, TInt aLength, TInt aMaxLength)which sets the length and maximum length (see Figure 5.6).5Type 2MaxLengthlength660x02003D48Figure 5.6Hello\0TPtr (type 2) pointing to raw data ‘Hello’Type 4 TPtr DescriptorsWhile a type 2 TPtr points to data, a type 4 TPtr points to anotherdescriptor.
A type 4 TPtr can only be created by calling HBufC::Des()4L indicates to the compiler that ”Hello” should be treated as a wide string, do notconfuse it with L.5There is also a constructor that doesn’t take the length as a parameter: TPtr::TPtr(TUint16 *aBuf, TInt aMaxLength). If you use this, be aware that the length of thedescriptor is 0 after construction.98DESCRIPTORSor TBufC::Des(). It is used to indirectly modify the contents of theseotherwise constant descriptors._LIT(KTxtHello, "Hello");_LIT(KTxtString, "Overwrite me");HBufC* hbuf = KTxtString().AllocL();// hbuf contains "Overwrite me"TPtr ptr = hbuf->Des();// points to the hbuf contentsptr = KTxtHello;// hbuf now contains "Hello"delete hbuf;This code copies the string ‘Hello’ into the hbuf variable.
Changesto the length of a type 4 TPtr also changes the length of the HBufC itpoints to, so in the example above, after the assignment, the length ofboth hbuf and ptr is five (see Figure 5.7).Type 4MaxLengthlength5120x02003D48Type Length05HFigure 5.7elloTPtr (type 4) pointing to an HBufC descriptorBe aware that if you have more than one type 4 TPtr pointing tothe same HBufC or TBufC, then modifications made via one are notreflected in the others.If you are using TPtr’s assignment operator there is some unexpectedbehavior that you need to be aware of – see Section 5.11.Using TPtr::Set()TPtr and TPtrC both have a Set() method for changing what theypoint to:_LIT(KHello, "Hello");_LIT(KWorld, "World");TPtrC hello(KHello); // contains "Hello"TPtrC world(KWorld); // contains "World"world.Set(hello);// world now contains "Hello"Note that if you wanted to indicate that the data the TPtrC pointsto should not be changed then you can declare it to be const.