(內容出自《把脈VC++》,挺好的一本書,下面內容是我整理摘錄的兩小節,順便吐槽微軟還真是整天把C搞的多複雜,讓人找來找去)
4.5.3 TCHAR、_T與_TEXT
計算機最初使用的不是UNICODE,最初的系統和程序都採用的是ANSI或者MBCS,那麼,問題來了:我們開發程序的時候,是採用char還是wchar_t?觀察如下代碼:
char msg[] = "學習C++";
當我們準備採用wchar_t時,則需要改成:
wchar_t msg[] = L"學習C++";
太麻煩了!幸運的是,Visual C++的開發者預知到了這樣的麻煩,他們從而爲此造出了一批宏,這些宏看起來亂七八糟的,但是確實解決了我們的問題,且看一段代碼:
TCHAR msg[] = _T("學習C++");
這段代碼中,msg到底是char數組還是wchar_t數組呢?Visual C++的解釋是,如果需要它是char數組,那麼它就是char數組;否則,它就是wchar_t數組。這樣的魅力來源於宏TCHAR的定義:
typedef unsigned char CHAR;
typedef unsigned wchar_t WCHAR;
#ifdef UNICODE
typedef wchar_t TCHAR;
#else
typedef unsigned char TCHAR;
#endif
由此可以看出,CHAR實際上就是unsigned char,WCHAR爲wchar_t,而TCHAR根據是否支持UNICODE而不同。宏UNICODE由此變得尤其重要,當我們定義了UNICODE宏,就相當於告訴了編譯器:我準備採用UNICODE版本。這個時候,TCHAR就會搖身一變,由unsigned char變成了wchar_t。
Visual C++項目屬性中都包含一項字符集的設置,如圖4-14所示。很容易理解,它與宏UNICODE之間存在着某種關係(還有宏MCBS,爲了簡化討論,在此省略)。
(點擊查看大圖)圖4-14 在Visual C++中設置項目採用的字符集 |
前面分析了TCHAR,接下來再來看看_T的含義:
#define _T(x) __T(x)
#define _TEXT(x) __T(x)
#ifdef UNICODE
#define __T(x) L ## x
#else
#define __T(x) x
#endif
同理,當UNICODE宏被定義,"_T("學習C++")"會解釋成"L"學習C++"",否則它只將其解釋成""學習C++""。
因此,我們建議這樣書寫代碼:
TCHAR msg[] = _T("學習C++");
除TCHAR之外,Windows還定義了一系列的包含T的宏:
#ifdef UNICODE
typedef WCHAR TCHAR, * PTCHAR ;
typedef LPWSTR LPTCH, PTCH, PTSTR, LPTSTR ;
typedef LPCWSTR LPCTSTR ;
#else
typedef char TCHAR, * PTCHAR ;
typedef LPSTR LPTCH, PTCH, PTSTR, LPTSTR ;
typedef LPCSTR LPCTSTR ;
#endif
4.5.4 strcpy、wcscpy與_tcscpy
C++標準庫函數提供了字符和字符串的操作函數,並提供了其UNICODE版本,如:
char *strcpy(char *strDestination, const char *strSource);
wchar_t *wcscpy(wchar_t *strDestination, const wchar_t *strSource);
wcscpy()即爲strcpy()的寬字符版本,與_T類似的,Visual C++提供了類似的同名函數:
#ifdef UNICODE
#define _tcscpy wcscpy
#else
#define _tcscpy strcpy
#endif
因此我們建議這樣書寫代碼:
TCHAR src[] = _T("學習C++");
TCHAR dest[20];
_tcscpy(dest, src);
比如,在使用printf()的時候,我會嘗試使用_tprintf()。
同樣的版本問題一樣會困擾着main()函數:
main( int argc, char *argv[ ], char *envp[ ]);
wmain( int argc, wchar_t *argv[ ], wchar_t *envp[ ]);
再來看_tmain()的定義:
#ifdef UNICODE
#define _tmain wmain
#define _tWinMain wWinMain
#else
#define _tmain main
#define _tWinMain WinMain
#endif
這就是爲什麼Win32控制檯項目默認輸出,提供一個_tmain()函數的緣故。