2017-11-11 162 views
0

我用來對付ASCII字符串但現在UNICODE我太多困惑的一些術語:爲什麼我們從MultiByte轉換到WideChar?

什麼是多字節字符,什麼是widechar有什麼區別? 多字節是指在內存中包含多個字節的字符,而widechar只是一種表示它的數據類型?

  • 我們爲什麼要從MultiByteToWideCharWideCharToMultiByte轉換?

如果我聲明是這樣的:

wchar_t* wcMsg = L"مرحبا"; 
MessageBoxW(0, wcMsg, 0, 0); 

它正確地打印消息,如果我定義UNICODE但爲什麼我沒有從這裏WideCharToMultiByte轉換?

  • 什麼角色之間的差異設定在我的項目:_MBCSUNICODE

  • MSDN將「Windows API」混淆的最後一件事是UTF-16。

任何人都可以解釋一些例子。一個很好的說明真的很感激。

+2

操作系統使用utf16編碼的字符串作爲其本機字符串類型。不使用wchar_t或std :: wstring足夠用於「ASCII字符串」是程序員最終使用MultiByteToWideChar很多。這並不是特別錯誤,只是效率低下,但是用ASCII編碼的字符串編寫阿拉伯語當然沒有什麼希望。 C++和低效不應該是一個句子或程序中使用的兩個單詞。考慮使用像Qt這樣的UI框架來減輕痛苦。 –

+0

@HansPassant:謝謝。如果你添加一個答案呢?這將是非常有利的。 – WonFeiHong

+0

「我習慣於處理ASCII字符串」:這非常可疑。如果您一直在調用MessageBoxA等Win32 API函數,讀取或寫入文本文件,讀取或寫入控制檯或使用C +庫,您一直在使用用戶的「locale」,它指定了像CP437這樣的字符編碼,Windows-1252或類似的,幾乎肯定不是ASCII。 –

回答

2

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()(不WA後綴) 如果設置您的項目以「使用多字節字符集」,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

+4

年代學不太正確。 Unicode聯盟最初使用16位字符集,推薦的編碼是使用16位單元。這種編碼被稱爲「Unicode」。 Windows遵循了建議,並將其編碼稱爲「Unicode」。在Windows NT發佈後很長時間,Unicode聯盟直到1996年才轉換爲32位字符集。因此,在設計Windows時,調用編碼爲「Unicode」的16位字符是正確的。 (爲了讓事情變得更加混亂,Unicode聯盟後來縮小爲26位字符集。) –

+1

噢好吧謝謝,然後我誤會了。我會盡力解決這個問題。 – user2328447

+1

(更正:Unicode目前是一個21位字符集,而不是26.有17個平面,每個平面都有65536個字符。) –

相關問題