1. 程式人生 > 實用技巧 >C++開發時字元編碼的選擇

C++開發時字元編碼的選擇

最近看了很多有關字元編碼的討論帖子, 自己也做了很多嘗試, 針對linux和windows上字元編碼的選擇做了個簡單整理, 在此做個記錄

首先是基礎編碼知識, 下面我列出的4個編碼方式或字符集是我們應該瞭解的

1. ANSI

2. UNICODE

3. UTF8

4. GB2312

這裡因為個人專業水平有限, 為了避免錯誤的解釋, 不對這些概念做詳細解釋, 而是貼出一些我查詢到的有用的資料

Unicode 和 UTF-8 有什麼區別 ---- https://www.zhihu.com/question/23374078

簡體漢字編碼方案(GB2312、GBK等)以及全形、半形、CJK ---- https://zhuanlan.zhihu.com/p/27099035

ANSI編碼與內碼表 ---- https://zhuanlan.zhihu.com/p/27136737

接下來是我自己的驗證和嘗試的過程以及自己的知識總結

先貼出來我在windows和linux環境下的測試程式碼, 編譯器我分別用linux GCC, MSVC v100 和 MSVC v141做了測試

 1 #ifdef _WIN32
 2 #if _MSC_VER >= 1600
 3 #pragma execution_character_set("utf-8")
 4 #endif
 5 #endif
 6 
 7 #include <stdio.h>
 8 #include <string
> 9 10 int main() 11 { 12 std::string testANSI = "中國"; 13 std::wstring testUNICODE = L"中國"; 14 15 printf("sizeof wchar_t : %lu \n", sizeof(wchar_t)); 16 printf("length of std::string : %lu \n", testANSI.length()); 17 printf("length of std::wstring : %lu \n", testUNICODE.length()); 18 19
printf("ANSI :"); 20 for (size_t idx = 0; idx < testANSI.length(); ++idx) 21 { 22 printf(" %hhx", testANSI[idx]); 23 } 24 printf("\n"); 25 26 printf("UNICODE :"); 27 for (size_t idx = 0; idx < testUNICODE.length(); ++idx) 28 { 29 printf(" %hx", testUNICODE[idx]); 30 } 31 printf("\n"); 32 33 return 0; 34 }

下面貼出不同平臺不同編碼方式下程式的輸出結果

1.windows環境下, 原始碼編碼為ANSI(本地gb2312)

2.windows環境下, 原始碼編碼為UTF8, 不使用execution_character_set巨集

3.windows環境下, 原始碼編碼為帶BOM的UTF8, 不使用execution_character_set巨集

4.windows環境下, 原始碼編碼為UTF8, 使用execution_character_set巨集

5.windows環境下, 原始碼編碼為帶BOM的UTF8, 使用execution_character_set巨集

6. Ubuntu linux環境下, 原始碼編碼為帶BOM的UTF8, 使用預設編碼方式編譯(這裡我指定的編碼方式即預設編碼)

7. Ubuntu linux環境下, 原始碼編碼在UTF8和GBK之間變換, 指定不同編碼輸出

MSVC v100和MSVC v141(對應vs2010和vs2017)的結果相同, 上方windows平臺執行截圖均為vs2017編譯執行結果

對上述結果進行總結

windows環境下, 原始檔編碼為不帶BOM的UTF8時, 由於編譯器沒能正常識別檔案編碼, string的內容被儲存為檔案的原本內容(utf8), wstring儲存的結果均是寬字元字串, 而非UNICODE字符集

windows環境下, 原始檔編碼為帶BOM的UTF8或ANSI時, 編譯器能夠正常識別檔案編碼(或者直接用本地編碼解析), string內容被儲存為gb2312字串, wstring內容均為UNICODE字符集

上面兩種情況, 僅當原始檔編碼為帶BOM的UTF8且程式使用execution_character_set巨集指明UTF8時, string內容才會被存為UTF8格式, UNICODE不受影響內容正常

linux環境下在檔案輸入編碼格式正確的情況下, 不管怎麼搞內容都一致, 且GCC編譯器可以相容帶BOM的UTF8原始檔

綜上, 總結我個人的看法建議 :

純Windows平臺開發, 原始碼使用ANSI, 字元型別選擇wchar_t, 杜絕char和string, 並且避免使用POSIX, 使用MSVC編譯器一定要在visual studio中選擇使用UNICODE字符集(影響_UNICODE和UNICODE兩個巨集宣告, 使用多位元組則會宣告巨集_MBCS)

跨平臺, 類Unix佔大頭則原始碼使用UTF8, Windows佔大頭則原始碼使用UTF8 with BOM並且選擇不受影響的編譯器, 字元型別選擇char, 在呼叫API和IO時根據需要進行轉換

重要的一點, 儘可能避免在原始碼中使用ASCII碼以外的任何字元(學好english是關鍵吶)

最後是我查閱和借鑑的資料,帖子,博文:

截止到 2017 年,C++ 對於 Unicode 支援情況如何 ---- https://www.zhihu.com/question/55601459

目前(2020 年)開發WINDOWS程式,用UNICODE還是多位元組更實際 ---- https://www.zhihu.com/question/364285465

[C/C++] 各種C/C++編譯器對UTF-8原始碼檔案的相容性測試(VC、GCC、BCB)---- https://www.cnblogs.com/zyl910/archive/2012/07/26/cfile_utf8.html

以上, 如有錯誤疏漏, 請務必指出, 任何問題歡迎討論, 轉載請註明, 感謝