I often use the Std :: String class of the Standard Template Library (STL) in the C program, but I have encountered problems when using Unicode. When using a conventional C style string, I can use Tchar and _T macro, so it can be compiled for Unicode or ASCII, but I always found that this ASCII / Unicode combination is difficult to use with STL's String class. . do you have any good advice?
Naren J.
Yes, once you know how tchar and _t work, then this problem is simple. Basic thinking is that tchar is char, or Wchar_t, depending on _unicode's value:
// Abridged from tchar.h
#ifdef _unicode
Typedef wchar_t tchar;
#define __t (x) l ## x
#ELSE
Typedef char tchar;
#define __t (x) x
#ENDIF When you select a Unicode character set in the engineering settings, the compiler will compile using the _unicode definition. If you choose MBCS (multibly character set), the compiler will not be defined by _unicode definition. Everything depends on the value of _unicode. Similarly, each Windows API function using the character pointer will have a A (ASCII) and a W (Wide / Unicode) version, and the actual definition of these versions is also determined by the value of _unicode:
#ifdef unicode
#define createfile createfilew
#ELSE
#define CreateFile CreateFilea
#endif, _tprintf and _tscanf correspond to Printf and Scanf. All versions of "T" have replaced Chars using Tchars. So how do you apply the above to std :: string? Very simple. STL already has a WSTRING class defined using wide character (defined in the xstring header file). String and wstring are template classes defined using TypedEf, based on Basic_String, with it to create any character types of string classes. The following is STL definition String and WString:
// (from include / xstring)
Typedef Basic_String Char_traits String; Typedef Basic_String Char_traits WString; Template is parameterized by the potential character type (char or wchar_t), so for TCHAR versions, what to do is to use TCHAR to imitate the definition. Typedef Basic_String Char_traits Allocator Tstring; now there is a TSTRING, which is based on tchar - that is, it either char, either Wchar_t, depending on the _unicoDe value. The above demonstrations are indicated by how the STL uses Basic_String to implement any type of string. Defining a new TypedEf is not the most effective way to solve this problem. A better way is based on String and WString to simply define TString, as follows: #ifdef _unicode #define tstring wstring #ELSE #define Tstring String #ndif This method is better because String and WString have defined String and WString, and why do you want to use templates to define a new and one of the same string classes? Temporarily call it tstring. You can use #define to define TString as string and wrstring, which avoids creating another template class (although today's compiler is very intelligent, if it discards the copy, I am not surprising). [Edit Update-2004/07/30: TypeDef does not create a new class, just introducing a limited range for a type, TypeDef will never define a new type]. Anyway, once you define TSTRING, you can encode like this: Tstring s = _t ("Hello, World"); _tprintf (_t ("s =% s / n"), s.c_str ()); Basic_String :: c_str method Returns a constant pointer pointing to the potential character type; here, the character type either const char *, or Const Wchar_t *. Figure 2 is a simple demonstration program illustrating the usage of TString. It writes "Hello, World" into a file and reports how many bytes written. I set up the project in order to generate the Debug version with Unicode and generate the Release version with MBCS. You can compile / generate and run the program separately, then compare results. Figure 3 shows the example of an example. Figure 3 TSTRING running By the way, MFC and ATL have now married so that they all use the same string implementation. The combined implementation uses a template class called CStringt, in a sense, its mechanism is similar to STL's Basic_String, with it to create a CSTRING class in accordance with any potential character type. Three string types are defined in the MFC contain file AFXSTR.H, as follows: Typedef atl :: cstringt Strtraitmfc Typedef atl :: cstringt Strtraitmfc Typedef atl :: cstringt Strtraitmfc So, which one is better, STL is also cstirng? Both are very good, you can choose your favorite one. But there is a problem to consider: is why you want to link which library, and whether you are already using MFC / ATL. From the point of view of the coding, I prefer the two features of CString: One is to initialize CString whether it is using wide character or char, which can be easily initialized. CSTRING S1 = "foo"; CSTRING S2 = _T ("bar"); these two initialization work normally because CString has made all necessary conversions. With STL strings, you must use _t () to initialize TString, because you can't initialize a WString via a char *, and vice versa. Its second is that CString automatically converts the LPCTSTR, you can code like this: CString S; LPCTSTR LPSZ = S; On the other hand, the use of STL must explicitly call C_STR to complete this conversion. This is really a bit a bit of picky, some people will argue that this can better understand when to conversion. For example, using CString in a function of C style variable parameters may have trouble, like Printf: Printf ("S =% S / N", S); // Error Printf ("S =% S / N", (LPCTSTSTSTSTSTS); / / must not have a mandatory type conversion, resulting in some garbage results, because PrintF wants S is char *. I am sure that many readers have made this mistake. Preventing this disaster is an unquestionable reason for the STL designer without providing a conversion operator. But insist that you want to call C_STR. Generally speaking, I like to use STL guys to tend to be theory and learn, while RedMontonians (translator: refers to Microsoft) more attention to practical and scattered. Oh, no matter what, the practical difference between std :: string and cstring is negligible.