C++輸出中文字符


注:本文轉載自互聯網,感謝作者整理!

 

1. cout

場景1
: 在源文件中定義 const char* str = "中文" 在 VC++ 編譯器上,由於Windows環境用 GBK編碼,所以字符串 "中文" 被保存為 GBK內碼,
編譯器也把 str 指向一個包含有 GBK編碼的只讀內存空間.
用 cout 輸出 str 時, 由於中文Windows環境用GBK編碼,所以把GBK編碼的 str 內容輸出到控制台,沒問題.

場景2: 在Linux 下編輯一個文件 const char* str = "中文", 由於Linux普遍使用 UTF8 編碼,所以在源文件里, "中文" 被保存為 UTF8內碼.
然后在Windows中打開這個源文件,由於Windows使用GBK編碼,所以VC++ 按照GBK去解釋被保存為 UTF8 內碼的 "中文", 顯示為亂碼.

2. wcout

在源文件中定義 const wchar_t* str = L"中文" 在 VC++ 編譯器上,由於指定了L,所以字符串 "中文" 被保存為UNICODE內碼(UCS2),
編譯器也把 str 指向一個包含有 UNICODE 編碼的只讀內存空間.
用 wcout 輸出 str 時, wcout 首先調用 wcstombs() (即根據當前 local 轉換, 如果沒有設置local,則是經典的C local, 不認識中文)把 str 的內容轉換后
交給控制台,結果自然什么都不顯示. (調試代碼可以知道VC++ 2010 實現是一個字符一個字符輸出,調用 wctomb_s)

原理
我們知道 cout 和 wcout 分別是 basic_ostream 的特化版本, 而 basic_ostream 調用 basic_streambuf 實際執行輸出動作,針對 wchar_t,
basic_streambuf有專門的特化函數,調用 fputwc 輸出一個寬字符,而 fputwc 需要調用 wctomb_s 把寬字符轉換后再輸出. 我們知道wctomb_s 是依賴 locale 的
由於默認情況下是C locale,所以用中文內碼調用 wctomb_s 會失敗.

解決辦法
設置當前系統的locale 替代默認的 "C" locale, 使 wctomb_s 等函數可以正常工作.
以下3種方法中的任意一種都可以達到目的.

1. C函數設置全局locale
setlocale(LC_ALL, "");

2. C++ 設置全局locale
std::locale::global(std::locale(""));

2. 單獨為 wcout 設置一個 locale
std::locale loc("");
std::wcout.imbue(loc);

結論
和Windows API 不同 C++中的各種 w版本的類或者函數並不能提高性能,因為它們都需要用 wc..to..mb 之類的函數轉換為ANSI兼容編碼然后調用標准庫函數.
或者,如果庫函數的實現者願意,針對Windows系統,寬字符的fputwc可以直接調用UNICODE版本的Windows API而不用轉換.但是這些都跟C++語言本身沒有什么關系.
由於Windows內核是UNICODE的,所以直接用 UNICODE 字符串調用 Windows API會有一點點好處.

C++設計者的出發點: 我不管你用什么字符編碼,與C++無關,要輸出時:如果是單字節字符或者多字節字符,直接輸出;如果是寬字符,則根據local轉換為多字節字符,然后再輸出.
即使將來UNICODE過時了(假設,假設而已),也不要緊,只要定義好新的local即可.對於C語言也是這樣.
Windows設計者的出發點: 統一使用 Unicode 寬字符,解決一切問題


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM