1. 程式人生 > >MSVC中C++ UTF8中文編碼處理探究

MSVC中C++ UTF8中文編碼處理探究

  字元編碼的問題,上大學那會兒就遇到過,一直都是雲裡霧裡,沒太搞清楚。最近又遇到了問題,想在C++的控制檯上輸出Utf-8編碼的漢字位元組流。嘗試了好多次都是亂碼,後來花了些時間查查資料,又和同事交流了一下,算是把C++上對於UTF8編碼的處理大概摸清楚了。 

字符集

   先說一個名詞:字符集,沒聽過的先百度一下,其實就是一種將字元編碼的格式,像我們常說的ASCII,UTF8,GBK都是常用的字符集。

  首先要清楚,從你在編輯器裡輸入一個UTF8漢字開始,到最終在控制檯上顯示出來,整個流程涉及到三個概念,分別是原始碼字符集,執行字符集,解析字符集。

  分別解釋一下:

  原始碼字符集

:就是你的原始碼文字檔案的字符集,如果你手頭有NodePad++這樣類似的文字編輯器你可以開啟看一下你的字符集,或者用Windows記事本另存為的時候也會顯示文字格式。要知道,你的原始碼文字檔案是以二進位制的形式躺在硬盤裡的,無論中文英文都一樣,當你輸入一個漢字後儲存關閉,這個漢字就是按照你指定的字符集轉換成二進位制編碼儲存下去的,當你在以這個格式開啟檔案時候,就再按照你指定的字符集把二進位制轉回來。如果兩次使用不同的字符集,也就會出現亂碼了。

  執行字符集:C++char* str= “我”;執行字符集決定了這行程式碼在編譯器進行編譯的時候str儲存的位元組到底是什麼,你可能會說原始碼字符集不是已經決定了這個

”我”的二進位制表示了麼,沒錯,但是這個執行字符集就是讓你在這裡對它再解釋一次。比如我原始碼字符集可能是UTF8的,但是我可以通過執行字符集來讓最終ptr儲存的是GBK的位元組編碼。

  解析字符集:最終要還原顯示這些二進位制位元組編碼的時候,就需要用到它。比如通過printf把前面的str顯示到控制檯時,這個printf就會按照解析字符集來解析這些位元組編碼,找到指定字元顯示出來。

  饒了一圈,好像也不是很亂,但是這裡面是有很多坑的。這幾個字符集的處理都是跟具體編譯器甚至作業系統相關的,不同的編譯器是有差別的,我這裡只說Windows7系統下VS2013(msvc編譯器)的環境。

VS2013中的字符集概念

1.對於原始碼字符集在VS2013檔案->高階儲存選項->編碼中可以檢視設定當前原始碼檔案的原始碼字符集。

2.對於執行字符集,VS2013預設根據系統的Locale來決定執行字符集,一般大家都是windows中文系統,Locale是中國,那麼就是GBK編碼。

3.對於解析字符集,我試了一下,如果沒有手動更改的話VS2013的標準輸入輸出(printf)到命令列也是根據系統Locael決定的,也就是GBK

 案例分析

   現在我們就分析一下,假如下面這段原始碼我們用UTF8格式儲存(無Bom).分析一下控制檯上顯示的結果。

1 char* str= “我”;
2 printf(“%s\n”,str);

1.首先這個程式碼檔案的文字中”我”這個漢字是以E68891三個位元組編碼的.

2.當編譯器編譯這段程式碼時,執行字符集預設是GBK,那麼編譯器要決定str的位元組內容,就要把文本里儲存的位元組內容轉為GBK,這裡就有個值得注意的問題,既然要轉換到GBK,就需要知道從什麼格式轉換到GBK,MSVC怎麼知道源格式呢?方法只有一個就是分析你的原始檔有沒有有BOM,要是有就按照BOM它就認為原格式就是BOM指定的格式(不瞭解BOM可以先百度一下),如果沒有BOM他就認為你的原始碼字符集是Locale關聯的。剛才說了我們是用UTF8無BOM格式儲存的原始檔,所以編譯器認為原始碼文字中的”我”是GBK編碼儲存的。

3.那從GBK到GBK,MSVC不會進行任何轉換,這裡有個小問題,提醒一下,這個程式碼應該是編譯不通過的,因為GBK中漢字是2個位元組表示的,而UTF8中是三個位元組,所以編譯器為了湊數會把”我”字後面的雙引號給吃掉,轉成了兩個GBK漢字編碼E688,9122(22是引號的UTF8編碼),沒有引號編譯器就會報錯,最簡單的解決辦法就是在在後面在加一個漢字變成偶數個就沒問題了。

4.程式執行起來後printf輸出到控制檯,這時候用到的解析字符集也是GBK的,就會用記憶體裡的E6889122GBK字符集裡找到對應編碼的漢字“鎴?”。這當然就錯了。

 解決方案 

   這就是我一開始出現的錯誤,既然知道問題了,那怎麼改呢,為了讓UTF8編碼的原始檔中的字可以顯示到命令列上,我們需要進行如下分析:

1.首先一定要在編譯的時候讓str的位元組內容是UTF8格式的才行,那就需要讓執行字符集是UTF8才行,前面說到MSVC執行字符集是根據Locale來決定的,本來是沒法更改的,但是微軟後來打了個小不定添加了一個預處理#pragma execution_character_set("utf-8")。來告訴編譯器執行字符集設定為UTF8。

2.編譯時候進行轉換到執行字符集需要知道原始碼字符集,之前我們是沒有帶BOM,這導致MSVC認為我們的原始檔是GBK編碼的,但其實我們是UTF8編碼,這就需要我們儲存原始碼的時候改為用UTF8帶BOM的格式。這樣就不會有問題了。

3.最後要顯示出來,既然記憶體裡是UTF8編碼,解析肯定也要按UTF8格式來解析,所以我們要把預設的解析字符集從GBK設為UTF8,最簡單的方法就是在輸出之前呼叫system(“chcp 65001”);這是命令列設定當前內碼表的命令。

  這樣應該就能正常顯示UTF8字元了,不過有個問題就是如果str用cout輸出的話,依然是亂碼,這個可能是因為cout有自己的解析字符集,不會隨著chcp命令改變。這個有待研究,哪位同學知道,可以留言告訴我。再說一點#pragma execution_character_set("utf-8")這個預處理在C++11裡已經不再需要了,C++11可以指定字串字面量的執行字元集了,u8”我”。就這麼簡單。但是vs2013並不支援這個功能。這篇文章講述的內容,並不在於如何把一個UTF8格式的C++字面量輸出到控制檯。而是在於通過這個例子來了解MSVC C++是如何處理UTF8中文字元的。

相關推薦

MSVCC++ UTF8中文編碼處理探究

  字元編碼的問題,上大學那會兒就遇到過,一直都是雲裡霧裡,沒太搞清楚。最近又遇到了問題,想在C++的控制檯上輸出Utf-8編碼的漢字位元組流。嘗試了好多次都是亂碼,後來花了些時間查查資料,又和同事交流了一下,算是把C++上對於UTF8編碼的處理大概摸清楚了。  字符集    先說一個名詞:字符集

[C/C++]_[VS2010原始碼使用UTF8中文字串被轉碼為ANSI的問題]

場景: 1.本以為vs設定了原始檔的UTF8編碼,程式碼中出現的中文字串就一定是utf8編碼了,可惜不是,如果原始碼中出現了中文字串,會在記憶體中轉碼為ANSI編碼。 Unicode(UTF8帶簽名) 內碼表(65001),從選單->檔案->高階儲存選項 設定

Servlet接受引數的中文編碼處理

在servlet中接收HttpServletRequest中引數的時候,如果有中文,不進行處理就會變成亂碼,甚是煩惱。由於經常會遇到這個問題,所以寫下來方便以後查用。 有一種簡單便捷的方式可以避免這種問題,程式碼如下: String reqstr = new

C# HttpRequest 中文編碼問題

nco 中文編碼 嘗試 webex 獲得 utility byte adt 字節數 GET方法: public string DoWebRequest(string url) { HttpWebResponse webRespon

Pycharm不支援中文編碼的解決方案。Pycharm中文報錯

Pycharm中不支援中文編碼的解決方案。Pycharm中文報錯 https://blog.csdn.net/zhonggaorong/article/details/53814215   版本資訊:  Pycharm 5.0.3  python &

幾種解決php+mysqluft-8中文編碼亂碼的辦法

當然發請求時,要在連線資料庫之後。   3.  最後是資料庫的編碼設定,建立資料庫的時候,請將“整理”設定為:“utf8_general_ci” 或“utf8_bin” ,當然選哪一個可以試試,哪一個可以就選哪個(我的兩個都可以),建立資料表的時候:如果是該欄位是存放中文的話,則需要將“整理”設定為:“ut

C++:中文編碼轉換

在介紹如何使用C++11標準庫進行中文編碼轉換之前,先說說一下byte string、multibyte string、wide string之間的區別。 byte string 由8位元的位元組組成的字串。由char表示位元組。因而字串長度=位元組數=char數 m

Pycharm不支援中文編碼的解決方案。Pycharm中文報錯。 Pycharm出現的部分快捷鍵無效及解決辦法

  Pycharm中不支援中文編碼的解決方案。Pycharm中文報錯。  1. 開啟Pycharm ---->  File ----> Default setting ------> Editor --

Spark踩坑系列4--spark 中文編碼處理

日誌的格式是GBK編碼的,而hadoop上的編碼是用UTF-8寫死的,導致最終輸出亂碼。研究了下Java的編碼問題。網上其實對spark輸入檔案是GBK編碼有現成的解決方案,具體程式碼如下import org.apache.hadoop.io.LongWritable imp

spark 中文編碼處理

日誌的格式是GBK編碼的,而hadoop上的編碼是用UTF-8寫死的,導致最終輸出亂碼。 研究了下Java的編碼問題。 網上其實對spark輸入檔案是GBK編碼有現成的解決方案,具體程式碼如下 import org.apache.hadoop.io.LongWrit

iOS判斷字串是否有中文處理方式

//判斷是否有中文 -(BOOL)hasChinese:(NSString *)str { for(int i=0; i< [str length];i++){ int

C#對URL中文亂碼處理

res quest 類庫 處理 odin .dll 前言 中文亂碼 ring 前言:UTF-8中,一個漢字對應三個字節,GB2312中一個漢字占用兩個字節。 不論何種編碼,字母數字都不編碼,特殊符號編碼後占用一個字節。 1、直接在C#後臺編碼URL參數 引用類庫:Syste

C++讀寫檔案,處理UTF8檔案,處理GBK中文字元

讀檔案 //從檔案中提取詞典 void getLexiconFromTrainData(char* filepath){ maxLength = 0; lexicalItemCount=0; allSentenceCount=0; wordCount=0

python處理中文編碼問題

今天在嘗試Python的CGI模組時遇到中文字元不能正確顯示的問題,很鬱悶. 在網上仔細找了找,終於解決了這個問題,現在將解決方 法陳述如下,以防下次失誤. 頁面原始碼如下 #-*- coding: utf8 -*- import cgitb , cgi cgitb.enable() form = cgi

C#StreamReader讀取中文時出現亂碼問題總結

utf8編碼 新的 conf window linu img utf8 enc ref 之前有一篇文章“ C#讀取及寫入配置文件教程”(http://blog.csdn.net/lisenyang/article/details/47291083)當中有一個問題就是在讀

圖像處理幾個基本的處理方法c#代碼實現

位圖 edi windows系統 process 圖案 電視 間接 做了 同步 圖像是人類獲取和交換信息的主要來源,因此,圖像處理的應用領域必然涉及到人類生活和工作的方方面面。隨著人類活動範圍的不斷擴大,圖像處理的應用領域也將隨之不斷擴大。(1)航天和航空技術方面的應用 數

python 中文url編碼處理

python url 中文編碼可以直接處理中英混排的urlfrom urllib.parse import quote (python3)from urllib import quote (python2) url = ‘http://www.baidu.com?search=中文在這裏‘

關於DjangoJsonResponse返回中文字典編碼錯誤的解決方案

keys **kwargs 技術 pytho div safe 關於 order res 解決方案:JsonResponse(data, json_dumps_params={‘ensure_ascii‘:False}) ! data是需要渲染的字典 def master

Python3如何解決中文亂碼與編碼的問題

lse 問題 ont 格式 enc strong 基本 encode code 1.解決亂碼問題: pyhton中內部所有編碼是Unicode,中文是gbk;正常情況下,我們輸出的是utf-8; 我們可以采用sys.getdefaulten

不依賴任何系統API,用c語言實現gbk/utf8/unicode編碼轉換

轉載地址:https://blog.csdn.net/bladeandmaster88/article/details/54837338 漢字'我' Unicode編碼是0x6211       01100010 00010001 UTF8編碼是&