1. 程式人生 > >微軟的字串問題(_T() 和_L() _TEXT __T,L及編碼)

微軟的字串問題(_T() 和_L() _TEXT __T,L及編碼)

C++主要使用的是C-Style字串,而M$在Windows中又增加了很多C-Style字串的變體。這個一多嘛,就容易亂~

  所謂字串,就是由字元組合而成,所以我們先來將將字元型別。

  首先,存在兩種最基本的字元型別:char和wchar_t。char大家都很熟悉了,我就跳過。至於wchar_t,是應用於UNICODE的寬字元,即一個字元2Bytes,16Bits。事實上,Windows中利用

typedef unsigned short wchar_t

定義wchar_t

  然後為了書寫方便(MS我也沒覺得有多大差別),M$又把那兩個基本字元型別重新的給他typedef了一遍,即:

typedef char CHAR
typedef wchar_t WCHAR

為了使得相容性更加,M$又定義了TCHAR資料型別:

#ifdef UNIOCDE
  
typedef WCHAR TCHAR
#else
  typedef 
CHAR TCHAR
#end if

這樣,你不用關心是要使用ANSI字串還是Unicode,編譯器會自動根據你的OS來選擇。

  然後,M$又利用上面的幾種基本資料型別,定義了一些字串指標型別。
LPSTR和LPCSTR:LPSTR是指向以0結尾的ANSI字串的指標,後者是const指標

typedef CHARLPSTR
typedef const 
CHARLPCSTR

LPWSTR和LPCWSTR:LPWSTR是指向以0結尾的UNICODE字串的指標,後者是const指標

typedef WCHARLPWSTR
typedef const WCHARLPCWSTR

同樣,為了擺脫對ANSI還是UNICODE的選擇麻煩,M$也增加了LPTSTR和LPCTSTR兩個字串指標型別。他們被如下定義:

typedef TCHARLPTSTR

#ifdef UNICODE
  
typedef LPSTR LPTSTR
#else
  typedef 
LPWSTR LPTSTR
#endif
/////////////////////////////////////
typedef const TCHAR
LPCTSTR

#ifdef UNICODE
  
typedef LPCSTR LPCTSTR
#else
  typedef 
LPCWSTR LPCTSTR
#endif

ps:你會在某些地方看到存在PSTR/PWSTR/PTSTR等等,與上面的只卻一個L的字串指標型別。實際上,這個是長指標和短指標問題。LPXX是長指標,PXX是短指標。不過在32Bit的系統上,二者已經沒有區別。

然後說說兩個比較成熟好用的字串型別:String和CString
String是C++的標準字串,需要string(不帶.h)頭檔案和std名字空間支援。
CString是M$為MFC設計的字串,功能更加強大,而且這玩意兒是安全的。需要atlstr.h檔案和MFC DLL的支援。不過目前已經有人將此型別從MFC中分離~

 為了增強程式的通用性,還必須注意以下幾點:

1、既然程式裡不能出現char,那表示字串時,就不能再習慣性的用char*了。應該改為TCHAR*,或者是PTSTR。後一種是 windows的變數,類似的有:PSTR、PTSTR、LPTSTR、LPSTR、PCTSTR等等等等。這也是讓人一開始接觸會頭大的地方。其實並非如此恐怖,我以PCTSTR為例做個解釋:P代表指標(和LP是一個東西,LP的本意是Long Pointer,16位windows時代的遺留物。),C代表const,T代表TCHAR,STR代表字串。所以PCTSTR其實就是const TCHAR* 的意思。而PSTR也就是char* 的意思。所以我們在表示字串時也不能使用PSTR等不帶T的變數型別名。

2、表示字串常量時,不能簡單的用雙引號括起來,因為那代表ascii字串。同樣也不能在前面加L,因為那代表unicode。我們的程式要做到的是通用性,即不是ascii也不是unicode。所以我們在字串前應該加的是TEXT,比如MessageBox(NULL,TEXT("Fypher"),TEXT("FF"),MB_OK)。TEXT還可用於字元。比如TCHAR m=TEXT('A');

3、TCHAR FF[50]。FF能裝多少字元?哈!不要習慣性的sizeof(FF)了,應該_countof(FF)或者sizeof(FF)/sizeof(TCHAR)。因為我們不確定TCHAR到底是char 還是 wchar_t。

4、該和一堆老朋友說再見了……我們不能再使用以前的字串處理函式或者字元處理函數了。比如strlen、strcat、strcmp等等等等……因為這些是ascii專用的,通通改成使用T家族的吧。字首都換成_tcs。比如_tcslen、_tcscat、_tcscmp等等……順便補充一下wcs字首是wchar_t使用的。恩,還有大家用得超爽的sprintf,今後就改成_stprintf了吧~呵呵。補充:swprintf是 wchar_t它家的。對了,windows認為_tcscpy、_tcscat等不安全,所以使用這些函式編譯器會報警。可以改用windows推出的 _tcscpy_s、_tcscat_s等“安全”函式,其實就是多了個引數用來指明緩衝區大小(記得用_countof哦~!^_^)。windows 還推出了形如StringCchCat的一套字串處理函式,我沒怎麼用過。windows也有一個字串比較函式CompareString。功能比 _tcscmp強大多了。比如可以設定忽略大小寫等。

5、IsTextUnicode函式可以用過一系列統計學的方法判斷某個字串是不是unicode字串。 MultiByteToWideChar和WideCharToMultiByte函式可實現Ascii和Unicode字串的相互轉化。這些的使用場合都不大。因為我們的程式應該做到“沒有”ascii和unicode。

6、恩,雖然絕大多數情況下應該使用TCHAR,但是記住GetProcAdress這個特殊的函式吧,它的引數只能是char*。因為在匯出函式表裡函式名是用ascii碼寫的……

7、最後一點,記得要#include <tchar.h>哦!呵呵~ 由於windows核心採用的是UNICODE,UNICODE版的程式必然比ASCII版的程式效率高(比如不用在呼叫函式時在堆裡分配空間把引數轉成 UNICODE,然後再呼叫UNICODE版的函式),所以我們最好是在程式的開頭加上#define UNICODE和#define _UNICODE,把程式轉換成UNICODE版的。如果程式的字串處理完全按照上面的通用性要求做了是不會出錯的。

8、注意:str字首與wcs字首都是標準C函式,需要有標準C執行庫才能夠使用。而lstr字首的是window提供的原生函式,不需標準C執行庫。

補充:

1)ASCII字串和寬字串

在應用程式中使用兩種字元:一是char型字串,負責記錄ANSI字符集,它是指向一個char陣列的指標,每個char型變數大小是一個位元組,字串是以0標誌字串結束的;一是wchar_t型的寬字串,負責描述unicode字符集,它是指向一個wchar_t陣列的指標,wchar_t字元大小為兩個位元組,字串以0標誌字串結束。

ANSI字元構造如下:

char *str1 = "ASCE";

UNICODE字元構造如下:

wchar_t *str2 = L"ASCE";

(注:在構造字串時使用關鍵字“L”,編譯器會自動生成所需要的寬字元)

 在驅動開發中,DDK將char和wchar_t替換成CHAR和WCHAR。

lstrcmp、lstrcmpi-對比串

lstrcmp 區分大小寫; lstrcmpi 不區分大小寫. 返回值: -1、0、1, 其中 0 表示相同.

lstrcmp與strcmp的區別是lstrcmp可以支援Unicode定義,也支援ASCII定義但是strcmp只支援ASCII定義