C 輸出中文字元

2021-07-03 15:59:00 字數 4136 閱讀 2268

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 首先呼叫 wcstomb_s() (即根據當前 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 寬字元,解決一切問題

原文:c/c++多位元組字元與寬字元的輸出

使用c++標準庫的iostream,可以方便地將控制台、檔案、字串以及其它可擴充的外部表示作為流來處理,但要處理中文,卻會碰到很多問題。本人原來沒怎麼用過這個iostream,這幾天嘗試用這個寫點東西,一會兒不能輸出中文,一會兒不支援中文檔名的,搞得頭大。網上搜了搜,沒有發現適用於所有情況的解決方案。不過後來自己經過多次測試,基本解決了這些問題,現在寫成文字作為乙個總結,也供碰到同樣問題的朋友參考。關於c語言中的 printf和wprintf的中文輸出,本文也進行了**。

需要說明的是,我的開發環境是vs 2005(標準庫當然也是微軟實現的),不保證其它環境下是相同的效果。

1、cout和wcout

在預設的c locale下,cout可以直接輸出中文,但對於wcout卻不行。對於wcout,需要將其locale設為本地語言才能輸出中文:

wcout.imbue(locale(locale(),"",lc_ctype)); // ①

也有人用如下語句的,但這會改變wcout的所有locale設定,比如數字「1234」會輸出為「1,234」。

wcout.imbue(locale(""));

2、ofstream和wofstream

在預設的c locale下,ofstream能正確輸出中文到檔案中,但不支援中文檔名;wofstream支援中文檔名,但不能向檔案中輸出中文。要解決這個問題,需要在開啟檔案之前將全域性locale設為本地語言。將全域性locale設為本地語言後,ofstream和wofstream的問題都解決了,但 cout和wcout卻不能輸出中文了。要讓cout和wcout輸出中文,需要將全域性locale恢復原來的設定,如下所示:

locale &loc=locale::global(locale(locale(),"",lc_ctype)); // ②

ofstream ofs("ofs測試.txt");

wofstream wofs(l"wofs測試.txt");

locale::global(loc); // ③

ofs<<"test測試"<<1234<

wofs<

3、printf和wprintf

加上這兩位c語言中的老兄,問題更加複雜。考慮如下語句(注意s的大小寫):

printf("%s", "multibyte中文/n"); // ④

printf("%s", l"unicode中文/n"); // ⑤

wprintf(l"%s", "multibyte中文/n"); // ⑥

wprintf(l"%s", l"unicode中文/n"); // ⑦

預設情況下,⑤、⑦兩條語句不能輸出中文,這兩條語句中字串的形式是unicode形式的。如果在所有輸出語句之前加上如下語句將c語言的全域性locale設定為本地語言(c語言中只有全域性locale)就可以正常輸出了:

setlocale(lc_ctype, ""); // ⑧

但這會導致cout和wcout不能輸出中文,將c語言的全域性locale恢復後cout和wcout就正常了,如下所示:

setlocale(lc_ctype, "c"); // ⑨

但恢復後,printf和wprintf輸出unicode文字又不正常了(輸出multibyte文字總是正常的)。總不能每寫乙個 printf/wprintf就設定一次然後再恢復一次吧?所以,建議不要混用iostream和printf/wprintf,實在要混用,那就讓 printf/wprintf只輸出multibyte字串,這樣不需要呼叫setlocale(),也就不會影響到cout和wcout。

總結總之,用iostream、printf/wprintf輸出中文,有點麻煩。概括起來要點如下:

如果要用wcout,需要在使用之前按語句①將其locale設定為本地語言; 

如果要用ofstream或wofstream,要在開啟檔案之前按語句②將全域性locale設為本地語言並儲存初始的全域性locale。然後在開啟檔案之後,按語句③將全域性locale恢復為初始值; 

不要混用iostream和printf/wprintf。如果要混用,只用printf/wprintf輸出multibyte字串; 

單獨使用printf/wprintf時,如果要輸出unicode字串,需要按語句⑧設定c語言的全域性locale。如果只輸出multibyte字串,則不需設定。 

最後再加上**者(本站站長)的一點話:

乙個程式,一般不會用兩種字串, 要麼用多位元組字串, 要麼用寬字串. 這樣,問題其實就很簡單, 沒作者說得那麼複雜.. 就算有時候需要轉換, 也有專門的函式

(例如,多位元組字元版本的程式,使用com元件, com元件需要寬字串. 則可以利用 _bstr_t, cstring

)..

輸出中文字元

輸出中文字元 要想在圖形中輸出中文字元,需要對輸出的中文字元進行編碼。使用iconv 函式,可以把一種編碼的字元,轉換為其他編碼的字元。下面介紹在圖形中輸出中文字元的方法,建立乙個新圖形 image imagecreate 400,200 設定背景,分配顏色 bgcolor imagecoloral...

php輸出中文字元

中文字元不可以使用imagettftext 函式在中直接輸出,如果要輸出中文字元,需要先使用iconv 函式對中文字元進行編碼,語法格式如下 string iconv string in charset,string out charset,string str 說明 引數 in charset是中...

Dev Cpp 輸出中文字元問題

最近 c 上機作業,vc 6.0 掛了沒法用,只好用 dev cpp 先頂替一下,然而在遇到輸出中文字元的時候出現了亂碼的情況,但這種情況又非常詭異。於是簡單了解了一下寫成此部落格。寫在前面 1.使用版本 5.11 2.gcc版本 4.9.2 問題描述 我需要輸出如下中文字元 按順序輸入 學號 姓名...