寬字元wchar t和窄字元char區別和相互轉換

2021-07-27 20:34:14 字數 3975 閱讀 9059

**:

1.    首先,說下窄字元char了,大家都很清楚,就是8bit表示的byte,長度固定。char字元只能表示asii碼表中的256個字元,包括前128個可見字元和後面的128個不可見字元。

wchar_t則是因為char所能表示的字元數太少(256個)而應運而生的,它的長度可以8bit,16bit,32bit,長度是與不同平台上的c庫相關的。其實這個長度是根據指定平台上想要用的encoding編碼方式來設定的。

在win32 msvc環境下,c庫中wchar_t的長度是2個byte,定義如下:

typedef unsigned short wchar_t; /* 16 bits */

它是按照utf-16編碼,但是因為wchar_t定義的長度只有2個位元組,所以它不能表示utf-16編碼長度為4個位元組的字元。即wchar_t只表示了utf-16的乙個子集。換句話話說,就是msvc下,wchar_t是utf-16編碼的,但是只能表示utf-16的乙個子集。按utf-16編碼時,大部分字元都以固定長度的位元組 (2位元組) 儲存.

在linux-x86的gcc環境下,c庫中wchar_t的長度為四個位元組,用ucs-4(即utf-32編碼方式)。

wchar_t就是儲存的字元的unicode碼值的編碼值,如windows下就是unicode碼值

的utf-16編碼值:

tchar wide = l"態";

在vs中watch為:  [0] 24577 l'態' wchar_t,即對應的十進位制為24577,而"態"unicode表中查到的碼值為十六進製制的6001,而0x6001對應的十進位制值就是24577.

tchar wide = l"a"; 因為a的unicode值與ascii值一樣,為97. 如果unicode碼值u小於0x10000,則u的utf-16編碼就是u對應的16位無符號整數。

所以可知,0x6001的utf-16編碼值就是0x6001。       

wchar_t   w1= l'中';  //unicode 編碼  ,寬字元字串前面要加l

wchar_t   w2= '中';   //ansi編碼

printf( "%0x   %0x ",w1,w2);

結果:4e2d   d6d0

雖然同樣是賦值給wchar_t,但是不同的編碼則值是不同的。同時也說明了wchar_t不光是可以儲存unicode寬字元,也可以儲存其它的編碼。但是如果是儲存的ansi編碼,則按照寬字元的格式輸出的是什麼呢?

wchar_t c= l'中';

wcout.imbue(locale("chs"));

wcout<

wchar_t c= '中';

wcout.imbue(locale("chs"));

wcout所以如果是需要寬字元引數的api裡傳入值為ansi編碼值的wchar_t可能會得到不可**的結果。

c/c++標準只是宣告wchar_t是乙個可以表示字符集中的任意乙個字元的足夠寬的變數型別。wchar_t可以用任何encoding編碼方式來儲存這個字元,如ansi, or ucs-2, or ucs- 4, 甚至是scu-128,只不過我們通常是用unicode編碼方式。wchar_t是與實現相關的。

所以為了可移植性,我們不能假定wchar_t的編碼方式,然後根據編碼方式做一些相關性操作,我們只能理解它為乙個足夠寬的字元型別。

參考:2.     ansi碼

ansi碼(american national standards institute),中文:美國國家標準學會的標準碼。

我們說的ansi碼,指windows平台的一種ascii擴充套件碼,他將ascii碼擴充套件到8bits,增加了0x80-0xff共128個字元。

對於ansi碼表而言,它相容ascii碼表,0x00~0x7f之間的字元,依舊是1個位元組代表1個字元。為使計算機支援更多語言,通常使用 0x80~0xff 範圍的 2 個位元組來表示 1 個非英語字元。

像gb2312, big5, jis 等使用ansi碼表的0x80~0xff範圍的2 個位元組來代表乙個字元的各種漢字延伸編碼方式,統稱為ansi 編碼。比如:漢字 '中' 在gb2312碼表中,使用 [0xd6,0xd0] 這兩個位元組儲存。ansi 編碼與utf-8一樣,也是一種編碼方式。

ansi用乙個位元組來表示英語字元,用兩個位元組來表示乙個非英語字元----這個字元位於某個字符集中的value。而字符集則可以是象gb2312,big5等在ascii碼表基礎上擴充套件的字符集。這些字符集中相容ascii碼表,並且加入了漢字(或繁體等)的字符集。

在vs 的c++環境下,可以通過如下方式檢視漢字的ansi編碼值。char型別取值範圍為-128~127。-42對應的char型別資料的原碼為「10101010」,反碼為"11010101",補碼為"11010110",即十六進製制為0xd6。同理-48則為0xd0.由此我們可知,ansi,是通過兩個窄字元char來表示乙個漢字的。

當我們 在vs裡輸入乙個「中」字時,其實它在gb2312裡對應的兩個字元值為0xd6和0xd0,那麼vs裡其實記錄的就是[0xd6,0xd0]這個編碼值。當我們電腦控制面板裡設定的system locale為中文的時候,[0xd6,0xd0]在vs裡就是呈現出「中」字;但是如果system locale設定為韓文時,[0xd6,0xd0]在vs裡就是呈現出的就是它所表示的韓文本。即同乙個ansi編碼值,對於不同的system locale值(不同的字符集),顯示出來的字元是不一樣的。

在vs工程屬性裡無論你選擇multi-byte character set 或 unicode character set字符集,char str = "中";這個表示式裡,"中"都是ansi編碼,編碼值都是[0xd6,0xd0]。即預設情況下,如果不加_t或l,預設情況下所有的字元都是ansi編碼。

3.   相互轉換:

轉換的時候是與encoding相關的,轉換完後顯示是和本地的language相關的。

windows:

multibytetowidechar和widechartomultibyte, multibytetowidechar可將utf-8編碼的多位元組或是ansi編碼的多位元組(即兩個位元組)等轉換為unicode的寬字元wchar_t。例如,兩個byte的窄字元表示的ansi漢字轉換為unicode的寬字元wchar_t。widechartomultibyte可以將wchar_t轉換utf-8或ansi 等編碼的多位元組。

linux:mbstowcs和wcstombs

multibytetowidechar根據介面中指定的encoding方式將source多字元轉換為對應的unicode值的寬字元widechartomultibyte則剛好相反,是根據指定的encoding編碼方式將unicode字元轉換為指定的編碼方式的多字元。

char str = "中";

int len=multibytetowidechar(cp_acp,0,str, -1, null,0);

wchar_t *w_string = new wchar_t[len];

memset(w_string,0,sizeof(wchar_t)*len);

multibytetowidechar(cp_acp, 0, str,-1,w_string, len);

執行結果:

則len的長度為2,得到兩個寬字元。*w_string則是'中'的寬字元值,*(w_string+1)則為結束符'\0'對應的寬字元值0.

詳細的轉換過程,下面的link中有詳細描述:

寬字元和窄字元

關於寬字元和窄字元之間的區別,以及為什麼當我們採用printf和char 的時候可以輸出乙個中文字元,大概是因為預設情況下的編碼方式是utf 8的編碼方式。具體的可以參考這兩篇部落格 關於寬字元和窄字元 和 關於寬字元 unicode或者寬字元都沒有改變char資料型態在c中的含義。char繼續表示...

窄字元轉寬字元

以前碰到這個問題整了很久,然後今天又碰到這個問題又整了很久,而且居然忘記了上次碰到過,誒看來是老了,所以還是做個筆記吧!ascii 字元 窄字元,8位 char,char lpcstr,lpstr pchar,pcstr pstr std string unicode 字元 寬字元,16位 lpcw...

寬字元和窄字元的轉換介面

寬字元和窄字元的轉換需求很經常會遇到,今天從網上找了兩個函式,修改了一下,奉獻給大家。include include std wstring towidestring const char pstr,int len std wstring towidestring const std string ...