撥開字符編碼的迷霧--編譯器如何處理文件編碼

1. Visual Studio字符集

使用Visual Studio創建的C++工程可以在工程屬性配置屬性-->常規中配置字符集:使用Unicode字符集(默認)、使用多字節字符集這個設置項不對字符編碼產生直接的影響(注意這裏的“直接”二字,第3節會說到),只會在工程屬性配置屬性-->C/C++-->預處理器加入相應的宏:

使用Unicode字符集 --> _UNICODE和UNICODE宏
使用多字節字符集   --> _MBCS宏

這幾個宏一般用來判斷是使用char還是wchar_t,在系統API中使用比較多,如MessegeBox通過是否定義了UNICODE宏來決定是使用LPCSTR還是LPCWSTR(LPCSTR即const char, LPCWSTR即const wchar_t):

#ifdef UNICODE
#define MessageBox  MessageBoxW
#else
#define MessageBox  MessageBoxA
#endif // !UNICODE

2. char和wchar_t

上面提到了,定義API時通過判斷UNICODE宏是否定義來決定是使用char還是wchar_t,那麼char和wchar_t有什麼不同了?

char和wchar_t是標準C/C++字符類型,並不是windows特有的。 char固定佔1個字節,wchar_t固定佔2個字節,從內存的角度來看,char、wchar_t和其他數據類型一樣,只是代表一段內存塊,用來存儲固定長度的二進制0或1。 在編程時,我們一般習慣於將字符串儲到char或wchar_t定義的內存空間中,將整形存儲在int定義的內存空間中。

所以,用char還是wchar_t來存儲字符,只是內存分配和數據存儲上面的事情,它們本身也是與字符編碼無直接關係的( 同樣注意這裏的“直接”二字,第3節會說到)。

3. 編譯器如何處理硬編碼字符

VC++編譯器編譯源代碼的步驟中,涉及編碼處理的步驟主要有2個:
第1步:預處理
1.1) 讀取源文件,判斷源文件採用的字符編碼類型。

編譯器判斷源文件編碼類型的步驟爲:
1. 若文件開始處有BOM(EF BB BF),則判定爲UTF-8編碼;
2. 若沒有BOM,則試圖從文件的前8個字節來判斷文件是否像UTF-16編碼,如果像,則就判斷爲UTF-16編碼。
3. 如果既沒BOM,也不是UTF-16編碼,則使用系統當前的代碼頁。

1.2) 將源文件內容轉成源字符集(Source Character Set),默認爲UTF-8編碼。

第2步:鏈接
2.1) 將1.2中得到的UTF-8轉爲執行字符集(Execution Character Set):

  • 對於寬字符串(即C/C++中以L標記的串,如L"abc", L'中'),執行字符集爲UTF-16編碼。
  • 對於窄字符串(和寬字符串對應,即不以L標記的串),執行字符集爲系統當前的代碼頁。

編譯器處理字符編碼過程

現在我們就可以說清楚Visual Studio字符集設置、char、wchar_t是如何間接影響到字符編碼的了:

Visual Studio字符集設置
      |
決定聲明哪一個宏(UNICODE還是_MBCS宏)
      |
宏又決定了API參數使用char還是wchar_t
      |
編譯器在進行【執行字符集】編碼時對char和wchar_採用不同的處理方式,從而對字符編碼產生了影響。

4. 徹底避免硬編碼字符亂碼

通過第3節的說明,很容易知道,要開發支持多語言,在任意語言(系統代碼頁)的windows環境下都正常編譯,且運行起來沒有亂碼的程序,需要遵循如下原則:

  1. 代碼文件採用UTF-8 with BOM編碼。
  2. Visual Studio字符集設置爲Unicode字符集。
  3. 使用wchar_t。

做到上面3步,你的代碼被別人從github上clone下來編譯,不會因爲你代碼中含有中文等字符,產生類似error C2015這樣的編譯錯誤,更不會產生亂碼。

本文介紹的方法只用來解決硬編碼字符亂碼的問題,至於數據傳輸中的亂碼,需要統一字符編碼來解決。

參考: https://blogs.msdn.microsoft.com/vcblog/2016/02/22/new-options-for-managing-character-sets-in-the-microsoft-cc-compiler

發佈了0 篇原創文章 · 獲贊 7 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章