ASCII字符串的char寬度爲一個字節(通常爲8位,很少爲7,9或其他位寬度)。這是一個遺留下來的時間,當內存大小非常小且昂貴時,處理器通常每個指令只能處理一個字節。
由於很容易想象,一個字節遠遠不足以存儲世界上所有可用的字形。僅中國人就有87.000個字形。字符通常只能處理256個字形(8位字節)。 ASCII只定義了96個字形(加上低32個字符,它們被定義爲不可打印的控制字符)。這對於英文上下文字符,數字和一些交織符號以及其他字形來說已經足夠了。
要處理比一個字節可容納的更多字形,一種方法是將基本字形存儲在一個字節中,其他常見字形存儲在兩個字節中,並且很少使用3字節或甚至更多字節中的字形。這種方法被稱爲Multi byte char set or Variable-width encoding。一個非常常見的例子是UTF 8,其中一個字符使用1到4個字節。它將ASCII字符集存儲在一個字節中(因此它也向後兼容ASCII)。最高位被定義爲一個開關:如果它被設置,其他字節將會跟隨。這同樣適用於以下字節,以便形成最多4個字節的「鏈」。 可變寬度的字符集的親的是:
- 與8位ASCII字符集向後兼容性
- 存儲器友好 - 使用作爲較少的內存儘可能
的缺點是:
- 處理更困難,處理器更昂貴。您不能簡單地迭代一個字符串,並假定每個
myString[n]
都提供一個字形;相反,如果有更多的字節在後面,你必須評估每個字節。
另一種方法是將每個字符存儲在由n個字節組成的固定長度字中,該字長度足以容納所有可能的字形。這被稱爲固定寬度字符集;所有的字符都有相同的寬度。一個衆所周知的例子是UTF32。它是32位寬,可以將所有可能的字符存儲在一個字中。固定寬度字符集的pro和con顯然是可變寬度字符集的反面:內存較重但更容易迭代。
但是,即使在UTF32可用之前,Microsoft也選擇了它們的本地字符集:它們使用UTF16作爲Windows的字符集,它使用的字長至少爲2個字節(16位)。這足以存儲比單字節字符集更多的字形,但不是全部。考慮到這一點,微軟在「多字節」和「Unicode」之間的區別在今天有點誤導,因爲它們的unicode實現也是一個多字節字符集 - 只有一個字形的最小尺寸更大。有人說這是一個很好的妥協,有人說這是兩個世界中最糟糕的 - 無論如何,就是這樣。當時(Windows NT)它是唯一可用的Unicode字符集,從這個角度來看,它們在多字符和Unicode之間的區別在當時是正確的(參見Raymond Chen的評論)
當然,如果你想將一個字符串以一種編碼(比如UTF8)轉換爲另一種(比如說UTF16),您必須轉換它們。那就是MultiByteToWideChar
爲你做的,WideCharToMultiByte
反過來。還有一些其他的轉換函數和庫。
這種轉換的成本相當多的時間,所以得出的結論是:如果你大量使用字符串和系統調用,爲性能着想,你應該使用操作系統的本地字符集,這將是UTF-16在你的案件。
因此,對於你的字符串處理,你應該選擇wchar_t
,在Windows的情況下意味着UTF16。不幸的是,wchar_t
的寬度可能因編譯器而異;在Unix下它通常是UTF32,在Windows下是UTF16。
_MBCS
是一個自動的預處理器定義它告訴你,你已經定義你的角色設置爲多字節,UNICODE
告訴你,你已經將它設置爲UTF-16。
你甚至可以在一個程序中,這已經不是UNICODE
限定設置寫
wchar_t* wcMsg = L"مرحبا";
MessageBoxW(0, wcMsg, 0, 0);
。前綴L"
定義了您的字符串是一個UNICODE
(寬字符)字符串,您可以使用它調用系統函數。
不幸的是,你可以不寫
char* msg = u8"مرحبا";
MessageBoxA(0, msg, 0, 0);
的字符集的支持已經改進了C++ 11,所以你也可以通過前綴u8
定義字符串UTF8。但「A」後綴的窗口函數不理解UTF8。 (另請參閱https://stackoverflow.com/a/504789/2328447) 這也建議在Windows/Visual Studio下使用UTF16又名UNICODE。
設置你的項目爲「使用多字節字符集」或「使用Unicode字符集」也改變了很多其他角色依賴定義:最常見的是宏TCHAR
,_T()
和所有的字符串相關的Windows功能,而不後綴,例如MessageBox()
(不W
或A
後綴) 如果設置您的項目以「使用多字節字符集」,TCHAR
將擴大到char
,_T()
將擴大到什麼,和Windows功能將得到A
後綴連接。 如果您將項目設置爲「使用Unicode字符集」,TCHAR
將擴展爲wchar_t
,_T()
將擴展爲L
前綴,並且Windows函數將獲得附加的W
後綴。
這意味着,書寫
TCHAR* msg = _T("Hello");
MessageBox(0, msg, 0, 0);
將與多字節字符集或Unicode集編譯兩者。你可以在MSDN找到關於這些主題的綜合指南。
不幸的是
TCHAR* msg = _T("مرحبا");
MessageBox(0, msg, 0, 0);
仍然無法工作時,選擇「使用多字節字符集」 - 在Windows功能仍然不支持UTF8,你甚至會得到一些編譯器警告,因爲你定義了unicode字符,這些字符包含在未標記爲Unicode的字符串中(_T()
未擴展爲u8
)
操作系統使用utf16編碼的字符串作爲其本機字符串類型。不使用wchar_t或std :: wstring足夠用於「ASCII字符串」是程序員最終使用MultiByteToWideChar很多。這並不是特別錯誤,只是效率低下,但是用ASCII編碼的字符串編寫阿拉伯語當然沒有什麼希望。 C++和低效不應該是一個句子或程序中使用的兩個單詞。考慮使用像Qt這樣的UI框架來減輕痛苦。 –
@HansPassant:謝謝。如果你添加一個答案呢?這將是非常有利的。 – WonFeiHong
「我習慣於處理ASCII字符串」:這非常可疑。如果您一直在調用MessageBoxA等Win32 API函數,讀取或寫入文本文件,讀取或寫入控制檯或使用C +庫,您一直在使用用戶的「locale」,它指定了像CP437這樣的字符編碼,Windows-1252或類似的,幾乎肯定不是ASCII。 –