MinGW-W64使得printf、cout、wprintf、wcout顯示出中文的種種
使用MinGW-W64-gcc 4.9.2 的64位 posix執行緒 seh異常機制的編譯器。它內建了iconv支援,可以在UTF-8與gbk之間來回轉碼,這個很重要。
說明:printf、cout、wprintf、wcout這些如何輸出中文,C/C++語言標準完全沒提其實現細節。所以這些是針對具體的編譯器環境而不同的。MinGW-W64、Linux GCC、Microsoft Visual C++都有所出入。
1 為使得printf顯示出中文,僅需要
gcc 命令列選項-fexec-charset=gbk
這意味著編譯器生成的可執行檔案的字串的內容都是按照gbk編碼的。在Windows環境下呼叫相應的C的stdout,正確顯示毫無問題。
2 為使得cout顯示出中文,僅需要
gcc 命令列選項-fexec-charset=gbk
這意味著cout應該是完全基於C的stdout實現。
3 使wprintf能輸出漢字,需要且僅需要這一行:
_setmode(_fileno(stdout), _O_WTEXT); // 需要 #include <io.h> 和 <fcntl.h>
及gcc 命令列選項-fexec-charset=gbk
但是在Visual C++與Linux gcc中,都不支援上述_setmode函式,雖然這兩個編譯器已經充分實現了wprintf、wcout輸出中文。
但是,上述_setmode語句會造成wcout輸出中文與英文字元時一片亂碼!
可見,wprintf是使用了C語言的標準輸出stdout。僅此而已。至於stdout應該採取的預設編碼字符集,由gcc 命令列選項-fexec-charset=gbk指定即可。
4 為使得wcout輸出中文,僅需要下述2條語句:
setlocale(LC_ALL, ""); // 需要 #include <locale>
std::ios_base::sync_with_stdio(false); // 缺少的話,wcout輸出的 wchar_t字串會漏掉中文字元
/* ios_base::sync_with_stdio 決定 C++ 標準 streams (cin,cout,cerr...) 是否
* 與相應的 C 標準程式庫檔案 (stdin,stdout,stderr) 同步,
* 也就是是否使用相同的 stream 緩衝區,預設情況是同步的。
* 但由於同步會帶來某些不必要的負擔,因此該函式作用就是我們自己可以取消同步
* std::ios::sync_with_stdio(false);
* 注意:必須在任何 io 操作之前取消同步
*/
完全不需要 std::wcout.imbue(std::locale("")); // 使 wcout 使用操作系環境中預設的 locale
由此可見,wcout是獨立於C的標準輸出stdout而獨立實現的;且在把寬字元轉換為作業系統預設字元編碼時,使用了C語言標準的locale設定(即setlocale函式),沒有setlocale函式的設定,僅靠gcc命令列選項gcc 命令列選項-fexec-charset=gbk是不行的。
僅此而已。
5 示例程式
#include <iostream>
#include <locale>
#include <cstdio>
#include <io.h>
#include <fcntl.h>
int main(void)
{
printf("printf的內容\n");
std::cout << "cout 的內容" << std::endl;
//fflush(stdout); //must be done before _setmode 實測不需要這行
//_setmode(_fileno(stdout), _O_WTEXT); // 需要 #include <io.h> 和 <fcntl.h>
wchar_t t[] = L"pure english\n";
wprintf(L"wprintf: %ls", t);
wprintf(L"wprintf: C 寬字元字串\n");
//setlocale(LC_ALL, ""); // 需要 #include <locale>
//std::ios_base::sync_with_stdio(false); // 缺少的話,wcout wchar_t 會漏掉中文
/* ios_base::sync_with_stdio 決定 C++ 標準 streams (cin,cout,cerr...) 是否
* 與相應的 C 標準程式庫檔案 (stdin,stdout,stderr) 同步,
* 也就是是否使用相同的 stream 緩衝區,預設情況是同步的。
* 但由於同步會帶來某些不必要的負擔,因此該函式作用就是我們自己可以取消同步
* std::ios::sync_with_stdio(false);
* 注意:必須在任何 io 操作之前取消同步
*/
//std::wcout.imbue(std::locale("")); // 使 wcout 使用客戶環境中預設的 locale
std::wcout << L"wcout: pure english" << std::endl;
std::wstring u = L"wcout: C++ 寬字元版 string";
std::wcout << L"wstring u 的內容是:" << u << std::endl;
std::wcout << L"wstring u 的字元數為:" << u.size() << std::endl;
return 0;
}
ps.
On Windows, the only way to achieve direct Unicode output is via WriteConsoleW(). The MS CRT (2008 and newer) provides a way to use C/C++ I/O facilities for direct Unicode output:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <fcntl.h>
#include <io.h>
#include <cstdio>
#include <cwchar>
#include <iostream>
using
namespace std;
int
main()
{
_setmode(_fileno(stdout), _O_U16TEXT);
fputws(L "\u00e7\n" , stdout);
wcout << L "\u00e7"
<< endl;
return
0;
} //main
|