Unicode環境下的字符差異
我總是對我的字符串使用_T()宏,這是為了讓我的代碼至少有Unicode的意識,當然,關於Unicode的話題不在這篇文章的討論範圍。_T()宏在8位字符環境下是如下定義的:
#define _T(x) x // 非Unicode版本(non-Unicode version)
而在Unicode環境下是如下定義的:
#define _T(x) L##x // Unicode版本(Unicode version)
所以在Unicode環境下,它的效果就相當於:
s.Format(L"%d", total);
如果你認為你的程序可能在Unicode的環境下運行,那麽開始在意用 Unicode 編碼。比如說,不要用 sizeof() 操作符來獲得字符串的長度,因為在Unicode環境下就會有2倍的誤差。我們可以用一些方法來隱藏Unicode的一些細節,比如在我需要獲得字符長度的時候,我會用一個叫做DIM的宏,這個宏是在我的dim.h文件中定義的,我會在我寫的所有程序中都包含這個文件:
#define DIM(x) ( sizeof((x)) / sizeof((x)[0]) )
這個宏不僅可以用來解決Unicode的字符串長度的問題,也可以用在編譯時定義的表格上,它可以獲得表格的項數,如下:
class Whatever { ... };
Whatever data[] = {
{ ... },
...
{ ... },
};
for(int i = 0; i < DIM(data); i++) // 掃描表格尋找匹配項。
這裏要提醒你的就是一定要註意那些在參數中需要真實字節數的API函數調用,如果你傳遞字符個數給它,它將不能正常工作。如下:
TCHAR data[20];
lstrcpyn(data, longstring, sizeof(data) - 1); // WRONG!
lstrcpyn(data, longstring, DIM(data) - 1); // RIGHT
WriteFile(f, data, DIM(data), &bytesWritten, NULL); // WRONG!
WriteFile(f, data, sizeof(data), &bytesWritten, NULL); // RIGHT
造成以上原因是因為lstrcpyn需要一個字符個數作為參數,但是WriteFile卻需要字節數作為參數。
同樣需要註意的是有時候需要寫出數據的所有內容。如果你僅僅只想寫出數據的真實長度,你可能會認為你應該這樣做:
WriteFile(f, data, lstrlen(data), &bytesWritten, NULL); // WRONG
但是在Unicode環境下,它不會正常工作。正確的做法應該是這樣:
WriteFile(f, data, lstrlen(data) * sizeof(TCHAR), &bytesWritten, NULL); // RIGHT
因為WriteFile需要的是一個以字節為單位的長度。(可能有些人會想“在非Unicode的環境下運行這行代碼,就意味著總是在做一個多余的乘1操作,這樣不會降低程序的效率嗎?”這種想法是多余的,你必須要了解編譯器實際上做了什麽,沒有哪一個C或C++編譯器會把這種無聊的乘1操作留在代碼中。在Unicode環境下運行的時候,你也不必擔心那個乘2操作會降低程序的效率,記住,這只是一個左移一位的操作而已,編譯器也很樂意為你做這種替換。)
使用_T宏並不是意味著你已經創建了一個Unicode的程序,你只是創建了一個有Unicode意識的程序而已。如果你在默認的8-bit模式下編譯你的程序的話,得到的將是一個普通的8-bit的應用程序(這裏的8-bit指的只是8位的字符編碼,並不是指8位的計算機系統);當你在Unicode環境下編譯你的程序時,你才會得到一個Unicode的程序。記住,CString 在 Unicode 環境下,裏面包含的可都是16位的字符哦。
Unicode環境下的字符差異