寬字符wchar_t和窄字符char——putwchar、wprintf


寬字符wchar_t 與 窄字符char

先說下窄字符char,這個大部分讀者應該很清楚,char類型的變量占一個字節(byte)(也就是8個bit(比特)),能表示256個字符,那char的范圍有兩種

第一種(signed char):-128~127

第二種(unsigned char):0~255

對char的范圍感興趣的讀者可以看一下這篇文章:淺談char類型范圍

 

但C標准並沒有規定char 應該是unsigned還是signed,C標准定義了三種類型:char、signed char、unsigned char在不同的編譯器下char可能是有符號數,也有可能是無符號數(意思是取決於編譯器

那么怎樣確定char是有符號數還是無符號數呢,有兩種方法

方法一:使用CHAR_MIN(注意:CHAR_MIN這個宏是在stdlib.h這個頭文件中定義的)

運行結果:

 

方法二:給char類型的變量賦值負數(如果char在編譯器上是有符號數,那么賦值只要是大於等於-128的數都可以正常打印)

運行結果:

上述兩種方法都可以用來確定char是無符號數還是有符號數(感興趣的讀者可以自行測試一下char的邊界,如果char是有符號數,可以給char賦值127或128來看一下會出現什么結果)

 

現在來說下寬字符wchar_t,先來看下char和wchar_t在存儲空間上的差別

運行結果:

從上面可以看出char占一個字節,wchar_t占兩個字節

下面來確定wchar_t是有符號數還是無符號數

運行結果:

從上面的結果可以看出wchar_t為無符號數,因為wchar_t占兩個字節,也就是16個比特(bit),最大值就是216-1=65535,到這里讀者可以看出寬字符窄字符最大的區別就是占字節大小的不同

寬字符 和 窄字符的賦值

關於窄字符char,大部分讀者都知道賦值的方法或者

而寬字符的賦值就不太一樣與窄字符相比,前面多了一個大寫的L這個L的作用就是告訴編譯器,這個字符串按照寬字符來存儲(一個字符占兩個字節)

按照之前的說法寬字符中一個字符占2個字節,那么mm[20]應該占40個字節,長度應該為11,下面來驗證一下

運行結果:

 

上面的代碼中用到了一個函數wcslen(),這個函數和strlen()其實是一個作用,只不過strlen適用於窄字符,wcslen適用於寬字符(讀者可以理解為wcslen是strlen對應的一個寬字符版本函數)

在C語言中的每個字符串處理函數都有對應的寬字符處理版本,下面列舉一些常見的寬字符處理函數

 

(圖片出處:https://www.cnblogs.com/mr-wid/archive/2012/10/07/2714392.html)

還有一點需要讀者注意的是,寬字符不等於Unicode,Unicode 是寬字符編碼的一種,只不過最常見的寬字符編碼方式就是Unicode了,UTF-16和UTF-32都是Unicode編碼。wchar_t也主要以這兩種方式實現

( c/c++標准只是聲明wchar_t是一個足夠寬的變量類型,可以表示字符集中的任意一個字符)

Unicode 是一套字符集,而不是一套字符編碼,嚴格來說,字符集和字符編碼不是一個概念:

字符集定義了字符和二進制的對應關系,為每個字符分配了唯一的編號。可以將字符集理解成一個很大的表格,它列出了所有字符和二進制的對應關系,

計算機顯示文字或者存儲文字,就是一個查表的過程。

而字符編碼規定了如何將字符的編號存儲到計算機中。如果使用了類似 GB2312 和 GBK 的變長存儲方案(不同的字符占用的字節數不一樣),那么為了區分一個字符

到底使用了幾個字節,就不能將字符的編號直接存儲到計算機中,字符編號在存儲之前必須要經過轉換,在讀取時還要再逆向轉換一次,這套轉換方案就叫做字符編碼

Unicode最長是32位,也就是4個字節,因為UTF-8是1~6個字節來存儲,當使用5或6字節存儲時,就不屬於Unicode編碼了

(感興趣的讀者可以看一下:刨根問底:C++中寬字符類型(wchar_t)的編碼一定是Unicode?長度一定是16位?

寬字符輸出函數

wprintf

wprintf無非就是printf的一個變種,和fprintf差不多只是格式上稍有區別

運行結果:

上面的代碼中,wprintf使用的格式控制符是%ls,%ls意味着將對應的參數會被當作基於寬字符的字符串(wide chraracter string )看待,而%s則意味着對應的參數會被當作普通字符串(multi-byte string)看待,

不要因為上面一句話而錯誤的認為%s只用於printf,而%ls只用於wprintf,其實在windows下使用都是可以正常輸出寬字符串的(其他操作系統下就不一定了)

%s
當使用 printf() 時,按照單字符格式輸出字符串
當使用 wprintf() 時,按照寬字符(兩字節)格式輸出字符串

 

%S
當使用 printf() 時,按照寬字符格式輸出字符串
當使用 wprintf() 時,按照單字符格式輸出字符串

 

注意這個H是寬字符串mm中的H,而不是ss中的H,ss中的字符串中的每個字符占一個字節,printf如果按照寬字符的標准來輸出就無法正常輸出了,而wprintf為什么只輸出了H呢,不是輸出字符串嗎,

下面我們用VS來看寬字符在內存中的存儲

 

從上圖就可以很清楚的看出“Hello World”這個寬字符串在內存中的存儲情況了,因為是寬字符所以大寫字母H用兩個字節表示(48 00),48是16進制轉成10進制就是72,剛好就是'H'的ASCII碼值的大小,如果按照單字符格式輸出(也就是一個字節一個字節的輸出)就輸出H,繼續往后,編譯器看到第二個字節00,就以為字符串已經到結束了,最后我們看到的結果就是只輸出了大寫字符H

 (本來對%S沒有什么疑問,就當成一個格式控制符記住就是,后來在微軟的官方文檔里找到了%S這個參數的解釋,如下圖)

上面這段話的意思大概是,%S這個格式說明符,表示使用與函數支持的默認寬度“相反”的字符寬度,有了這一段話,上面的就很好解釋了,printf因為默認支持的寬度是單字符,而%S偏要使用相反的,那么就

使用寬字符格式輸出,而wprintf默認支持的寬度是寬字節,%S偏要使用相反的,意思就是使用單字符格式輸出,這樣記起來就容易多了

 

如果想要輸出寬字符的單個字符,需要使用格式控制符%lc

(要清楚%ls和%s的意義在於指明的參數是何種字符串,而printf和wprintf的區別在於所使用的是不同類型的stream,不要混用 char 和 wchar_t 版本的流操作函數,否則會導致這些函數運行異常)

 putwchar

putwchar函數專門用來輸出一個寬字符,它和 putchar 的用法類似

wchar_t ch = L'Z'; putwchar(ch);

 運行結果:

 


免責聲明!

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



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