Wiley.Developing.Software.for.Symbian.OS.2nd.Edition.Dec.2007 (779887), страница 35
Текст из файла (страница 35)
Indescriptors there is an equivalent function to sprintf() called Format(), and in MakeName() the line would be: str.Format( L("%S%S"),KNamePrefix,aName). The Format() descriptor method iscovered in more detail in section 6.4.2.6.3 The Descriptor ClassesIn this section, we look closely at all of the descriptor classes.There are 12 descriptor classes available for the programmer to use.These are divided into three types: buffer, pointer, and heap. Bufferdescriptors contain their data buffers in the descriptor classes themselves;their class names begin with TBuf. Pointer descriptors contain a pointerto a data buffer located outside the descriptor; their names begin withTPtr. Heap descriptors are used for managing descriptors on the heap.Heap descriptor names begin with HBuf or RBuf.THE DESCRIPTOR CLASSES169A descriptor can be modifiable or non-modifiable.
A C (for constant)is appended to the class names mentioned above to indicate that thedescriptor is non-modifiable.Furthermore, a descriptor buffer can contain 8-bit or 16-bit data.Adding 8 or 16 at the end of the class name indicates this. So, forexample, TBufC16 is a 16-bit non-modifiable buffer descriptor.Listed here are all the descriptor classes that can be instantiated.These classes are directly instantiated without inheritance, and they aredefined in e32des8.h and e32des16.h in the <SDK InstallationDirectory>\epoc\include directory.•TBuf8<n>: modifiable, 8-bit buffer, n is the buffer size.•TBuf16<n>: modifiable, 16-bit buffer, n is the buffer size.•TBufC8<n>: non-modifiable, 8-bit buffer, n is the buffer size.•TBufC16<n>: non-modifiable, 16-bit buffer, n is the buffer size.• TPtr8: modifiable, 8-bit pointer descriptor.• TPtr16: modifiable, 16-bit pointer descriptor.•TPtrC8: non-modifiable, 8-bit pointer descriptor.• TPtrC16: non-modifiable, 16-bit pointer descriptor.•HBufC8: non-modifiable, 8-bit heap descriptor.• HBufC16: non-modifiable, 16-bit heap descriptor.•RBuf8: modifiable, 8-bit heap descriptor.•RBuf16: modifiable, 16-bit heap descriptor.16-Bit default for UnicodeMost times you will see strings represented with descriptor classes with nodata width appended to the class name (e.g., just TBuf).
If you leave thedata width off the class name, it defaults to a 16-bit descriptor. Actually,the default depends on whether the build is using a 16-bit Unicodecharacter set or not (remember descriptors are used mainly for strings).But since all current Symbian OS platforms use Unicode, then the defaultis always 16-bit. Examine the include file e32std.h if you are interestedin how this default mapping to the descriptor classes is accomplished.Since 8- and 16-bit descriptors behave identically in almost all respects,I will use the default 16-bit descriptors (by leaving the number off) forsimplicity for most of this chapter. Unless stated otherwise, you canassume that the code for 16-bit descriptors applies also to 8-bit descriptors.170STRINGS, BUFFERS, AND DATA COLLECTIONSDescriptor class hierarchyFigure 6.2 shows a class diagram of the descriptor classes.
As indicatedabove, the diagram shows 16-bit classes only – there is a separate, butequivalent hierarchy for 8-bit descriptors that start with TDesC8 (just tackan 8 on every class name, and you’ll have it).6.3.1 Descriptor Base ClassesTDes and TDesC are the base classes for descriptors, and they containmethods for operating on the descriptor’s buffer. As you can see, TDesinherits from TDesC. All modifiable classes inherit from TDes, whilethe non-modifiable ones inherit directly from TDesC. Why is this? Theanswer is simple: TDesC provides all the methods that involve onlyreading descriptor data. Since all descriptors allow reading, then it servesas a base for all descriptors.
TDes extends TDesC by adding the methodsthat involve writing descriptor data, which is why only the modifiabledescriptors inherit from it.TDesC- Type- iLength- read only descriptor methodsTDes- iMaxLength- methods that modify dataTBufCBaseTBufBaseTBuf<n>TPtrRBufFigure 6.2TPtrCTBufC<n>Descriptor Class DiagramHBufCTHE DESCRIPTOR CLASSES171Remember that when you see a reference to a TDesC object, it doesnot mean it represents only non-modifiable descriptors – modifiable onescan also be referenced through pointers or references of this type, but nowriting will be done on them. However, TDes pointers and referencescan only be used with modifiable descriptors.The TBufCBase and TBufBase classes shown in the class diagramare for implementation only and have no public methods or members,and thus will not be discussed.Earlier we discussed that, unlike traditional C-style arrays, descriptorscontain the size of their data buffer so that it can be safely accessed.
Thedescriptor size is stored as a member variable in TDesC. TDesC providestwo methods to access this size: Size() and Length(). Size() returnsthe buffer size in bytes. Length() returns the buffer size in either 8- or16-bit units depending on whether it is an 8- or 16-bit descriptor. Forexample, if a 10-character Unicode string is stored in a 16-bit descriptor,Length() will return 10 and Size() will return 20.Class TDes (which inherits from TDesC) adds an additional lengthvalue that specifies the maximum limit of the descriptor buffer. Thisis used for modifiable descriptors to ensure that write operations donot occur past the end of the allocated buffer.
Therefore, modifiabledescriptors have two lengths associated with them – the size of the datacurrently in the buffer (from TDesC) and the maximum size of the data(from TDes).TDes and TDesC cannot be directly instantiated; however, you willsee and use these types frequently in function prototypes.
Using baseclass references like this allows you to use descriptors without needingto know what kind of descriptor it is. However, as mentioned previously,while TDesC can represent all descriptors, TDes can only representmodifiable descriptors (e.g., TBuf). Furthermore, TDes and TDesC canonly represent 16-bit descriptors and TDes8 and TDesC8 can onlyrepresent 8-bit descriptors.In the following example:_LIT(KSuffix,".suffix");void AddSuffix(TDes& aString){aString.Append(KSuffix);}the function AddSuffix() will add the string ".suffix" to the end ofany modifiable descriptor type passed.6.3.2String LiteralsWe’ve already seen string literals defined in some of the examples usingLIT and L, but before moving on to describe the different descriptor172STRINGS, BUFFERS, AND DATA COLLECTIONStypes in detail, let’s look more closely at how string literals are handledin Symbian OS.String literals are used to store and reference strings in the code imageitself.
In C, you simply specify a quoted string (or one with an L prefixfor 16-bit strings) and the compiler stores it – along with a terminatingNULL – in the code image, and then substitutes a pointer to that location.This is simple and efficient for C since a pointer to a NULL-terminatedstring is how C uses strings.
An example of a C string declaration is:const char *str="Hello";LIT and L both take a quoted string as an argument and producea literal that appears, for all practical purposes, like a descriptor. Bothmacros are used often, but LIT is preferred because it is implementedin a very efficient way, such that no runtime class construction occurs.L, on the other hand, just instantiates a TPtrC descriptor at runtime,which is not as efficient.Here is an example of using LIT:_LIT(KMyString, "My String");This defines the literal KMyString, used to reference the string "MyString".
You can use KMyString as if it were a non-modifiabledescriptor – you can pass it to functions that accept TDesC arguments(but not TDes!), you can assign it to TDesC pointers, and you caneven call descriptor methods directly if you use the () operator (e.g.,MyString().Length()).The LIT macro creates a special class called TLitC for string literals.Let’s look at how the LIT macro is implemented._LIT(KMyString, "My String")expands to:const static TLitC<10> KMyString={9, L"My String"}The buffer data and its calculated size are initialized to data members ofa TLitC class.The class TLitC does not inherit from TDesC – but it appears inmemory like TBufC (see section 6.3.3).
This makes it possible for thecompiler to statically initialize the data since it is all in one class. This,along with some operators that cast its type to TDesC, provides anTHE DESCRIPTOR CLASSES173effective trick to allow you to store a TDesC-type descriptor in the codeimage without a constructor being called at runtime.Like LIT, the L macro also defines a literal that can be treatedas a TDesC (actually it is one in this case): L("Hello") expands toTPtrC((const TText *) L"Hello").When an L is encountered, a temporary TPtrC object is constructedand allocated.