日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++ unicode转换中文_彻底弄懂UTF-8、Unicode、宽字符、locale

發布時間:2024/9/19 c/c++ 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++ unicode转换中文_彻底弄懂UTF-8、Unicode、宽字符、locale 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

結論

寬字符類型wchar_t

locale

為什么需要寬字符類型

多字節字符串和寬字符串相互轉換

最近使用到了wchar_t類型,所以準備詳細探究下,沒想到水還挺深,網上的資料大多都是復制粘貼,只有個結論,也沒個驗證過程。本文記錄探究的過程及結論,如有不對請指正。

Unicode、UCS

UCS(Universal Character Set)本質上就是一個字符集。

Unicode的開發結合了國際標準化組織所制定的 ISO/IEC 10646,即通用字符集(

Universal Character Set, UCS)。Unicode 與 ISO/IEC 10646 在編碼的運作原理相同,但 The Unicode Standard 包含了更詳盡的實現信息、涵蓋了更細節的主題,諸如比特編碼(bitwise encoding)、校對以及呈現等。摘自(Unicode)

所以也可以簡單的理解為,Unicode和UCS等價,都是字符集。

UCS編碼的長度是31位,可用4個字節表示,可以表示2的31次方個字符。如果兩個字符的高位相同,只有低16位不同,則它們屬于同一平面,所以一個平面由2的16次方個字符組成。目前大部分字符都位于第一個平面稱為BMP。BMP的編碼通常以U+xxxx這種形式表示,其中x是16進制數。

比如中文“你”對應的UCS編碼為U+4f60,“好”對應的UCS編碼為U+597d。更多中文編碼可以在Unicode編碼表中查詢。

有了UCS編碼,任何一個字符在計算機中都最多可以用四個字節來表示,稱為碼點。

UTF8

現在有了UCS字符集,那么一個字符在計算機中真的要按四個字節(UTF-32)來存儲嗎?

答案是否定的,一方面每個字符都按四字節來存儲非常浪費空間,因為大部分字符都在BMP,只有后16位有效,前16位都是0。另一方面這與c語言不兼容,在c語言中0字節表示字符串的結尾,庫函數strlen等函數依賴這一點,如果按UTF-32存儲,其中有很多0字節并不表示字符串結尾。

Ken Thompson發明了UTF-8編碼,可以很好的解決以上問題。Unicode 和 UTF-8 之間的轉換關系表如下:

碼點起 值碼點 終值字節序列 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6

U+0000 U+007F 1 0xxxxxxx

U+0080 U+07FF 2 110xxxxx 10xxxxxx

U+0800 U+FFFF 3 1110xxxx 10xxxxxx 10xxxxxx

U+10000 U+1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

U+200000 U+3FFFFFF 5 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

U+4000000 U+7FFFFFFF 6 111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx


第一個字節要么最高位是0(ASCII碼),要么最高位都是1,最高位之后的1的個數決定了后面的有多少個字節也屬于當前字符編碼,例如111110xx,最高位之后還有4個1,表示后面的4個字節屬于當前編碼。后面的每個字節的最高位都是10,可以和第一個字節區分開來。后面字節的x表示的就是UCS編碼。所以UTF-8就像一列火車,第一個字節是車頭,包含了后面的哪幾個字節也屬于當前這列火車的信息,后面的字節是車廂,其中承載著UCS編碼。

以中文字符“你”為例,對應的Unicode為"U+4f60",二進制表示為0100 1111 0110 0000。按照表中的規則編碼成UTF-8就是11100100 10111101 10100000(0xe4 0xbd 0xa0)。

結論

Unicode本質是字符集,在這個集合中的任意一個字符都可以用一個四字節來表示。

UTF-8是編碼規則,可以通過這個規則將Unicode字符集中任一字符對應的字節轉換為另一個字節序列。UTF-8只是編碼規則中的一種,其它的編碼規則還有UTF-16,UTF-32等。

寬字符類型wchar_t

在介紹寬字符前先了解下locale。因為多字節字符串和寬字符串的轉換和locale相關。

locale

什么是locale

區域設置(locale),也稱作“本地化策略集”、“本地環境”,是表達程序用戶地區方面的軟件設定。在linux執行locale可以查看當前locale設置:

ubuntu@VM-0-16-ubuntu:~$ localeLANG=zh_CN.UTF-8LANGUAGE=LC_CTYPE="zh_CN.UTF-8"LC_NUMERIC="zh_CN.UTF-8"LC_TIME="zh_CN.UTF-8"LC_COLLATE="zh_CN.UTF-8"LC_MONETARY="zh_CN.UTF-8"LC_MESSAGES="zh_CN.UTF-8"LC_PAPER="zh_CN.UTF-8"LC_NAME="zh_CN.UTF-8"LC_ADDRESS="zh_CN.UTF-8"LC_TELEPHONE="zh_CN.UTF-8"LC_MEASUREMENT="zh_CN.UTF-8"LC_IDENTIFICATION="zh_CN.UTF-8"LC_ALL=

可以將locale理解為一系列環境變量。locale環境變量值的格式為language_area.charset。languag表示語言,例如英語或中文;area表示使用該語言的地區,例如美國或者中國大陸;charset表示字符集編碼,例如UTF-8或者GBK。

這些環境變量會對日期格式,數字格式,貨幣格式,字符處理等多個方面產生影響。

參考資料:

locale wiki

Environment Variables

如何設置系統默認的locale

修改配置文件/etc/default/locale,比如要將locale設為zh_CN.UTF-8,添加如下語句LANG=zh_CN.UTF-8

locale環境變量有何作用

以LC_TIME為例,該變量會影響strftime()等函數。size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr)

strftime根據format中定義的格式化規則,格式化結構timeptr表示的時間,并把它存儲在str中。

#include<locale.h>#include<stdio.h>#include<time.h>intmain(){time_tcurrtime;structtm*timer;charbuffer[80]; time( &currtime ); timer = localtime( &currtime );printf("Locale is: %sn", setlocale(LC_TIME,"en_US.iso88591")); strftime(buffer,80,"%c", timer );printf("Date is: %sn", buffer);printf("Locale is: %sn", setlocale(LC_TIME,"zh_CN.UTF-8")); strftime(buffer,80,"%c", timer );printf("Date is: %sn", buffer);printf("Locale is: %sn", setlocale(LC_TIME,"")); strftime(buffer,80,"%c", timer );printf("Date is: %sn", buffer);return(0);}

編譯后運行結果如下:

Localeis: en_US.iso88591Dateis: Sun07Jul201904:08:39PM CSTLocaleis: zh_CN.UTF-8Dateis:2019年07月07日 星期日16時08分39秒Localeis: zh_CN.UTF-8Dateis:2019年07月07日 星期日16時08分39秒

可以看到對LC_TIME設置不同的值后,調用strftime()會產生不同的結果。

char* setlocale (int category, const char* locale);可以用來對當前程序進行地域設置。

category:用于指定設置影響的范圍,LC_CTYPE影響字符分類和字符轉換,LC_TIME影響日期和時間的格式,LC_ALL影響所有內容。

locale:用于指定變量的值,上例中分別使用了"en_US.iso88591","zh_CN.UTF-8"和空字符串"",""表示使用當前操作系統默認的區域設置。

參考資料:

setlocale()

為什么需要寬字符類型

“你好”對應的Unicode分別為"U+4f60"和"U+597d”,對應的UTF-8編碼分別為“0xe4 0xbd 0xa0”和“0xe5 0xa5 0xbd”

多字節字符串在編譯后的可執行文件以UTF-8編碼保存

#include<stdio.h>#include<string.h>intmain(void){chars[] ="你好";size_tlen =strlen(s);printf("len = %dn", (int)len);printf("%sn", s);return0;}

編譯后執行,輸出如下:

len = 6

你好

od編譯后的可執行文件,可以發現"你好"以UFT-8編碼保存,也就是“0xe4 0xbd 0xa0”和“0xe5 0xa5 0xbd”6個字節。

strlen()函數只管結尾的0字節而不管字符串里存的是什么,所以len是6,也就是“你好”的UFT-8編碼的字節數。

printf("%sn", s);相當于將“0xe4 0xbd 0xa0”和“0xe5 0xa5 0xbd”6個字節write到當前終端的設備文件,如果當前終端的驅動程序能識別UTF-8編碼就能打印漢字,如果當前字符終端的驅動程序不能識別UTF-8就打印不出漢字。

寬字符串在編譯后可執行文件中以Unicode保存

#include<wchar.h>#include<stdio.h>#include<locale.h>intmain(void){ setlocale(LC_ALL,"zh_CN.UTF-8");//設置localewchar_ts[] =L"你好";size_tlen = wcslen(s);printf("len = %dn", (int)len);printf("%lsn", s);return0;}

編譯后執行,輸出如下:

len = 2

你好

對編譯后的可執行文件執行od命令,可以找到如下這些字節:

193 000302000100020` O 00} Y 00n 0001940002000100004f600000597d0000000a

00004f60正是“你”對應的Unicode,0000597d是“好”對應的Unicode。所以對于寬字符串是按Unicode保存在可執行文件中的。

wchar_t是寬字符類型。在字符常量或者字符串前加L就表示寬字符常量或者寬字符串。所以len是2。

wcslen()和strlen()不同,不是見到0字節就結束而是要遇到UCS編碼為0的字符才結束。

目前寬字符在內存中以Unicode進行保存,但是要write到終端仍然需要以多字節編碼輸出,這樣終端驅動程序才能識別,所以printf在內部把寬字符串轉換成多字節字符串,然后write出去。這個轉換過程受locale影響,setlocale(LC_ALL, "zh_CN.UTF-8");設置當前進程的LC_ALL為zh_CN.UTF-8,所以printf將Unicode轉成多字節的UTF-8編碼,然后write到終端設備。如果將setlocale(LC_ALL, "zh_CN.UTF-8");改為setlocale(LC_ALL, en_US.iso88591):打印結果中將不會輸出"你好"。

一般來說程序在內存計算時通常以寬字符編碼,存盤或者網絡發送則用多字節編碼。

多字節字符串和寬字符串相互轉換

c語言中提供了多字節字符串和寬字符串相互轉換的函數。

#include<stdlib.h>size_tmbstowcs(wchar_t*dest,constchar*src,size_tn);size_twcstombs(char*dest,constwchar_t*src,size_tn);

mbstowcs()將多字節字符串轉換為寬字符串。

wcstombs()將寬字符串轉換為多字節字符串。

考慮下面的例子:

#include<locale.h>#include<stdio.h>#include<time.h>#include<stdlib.h>#include<wchar.h>#include<string.h>wchar_t* str2wstr(constcharconst* s) {constsize_tbuffer_size =strlen(s) +1;wchar_t* dst_wstr = (wchar_t*)malloc(buffer_size *sizeof(wchar_t)); wmemset(dst_wstr,0, buffer_size); mbstowcs(dst_wstr, s, buffer_size);returndst_wstr;}voidprintBytes(constunsignedcharconst* s,intlen){for(inti =0; i < len; i++) {printf("0x%02x ", *(s + i)); }printf("n");}intmain(){chars[10] ="你好";//內存中對應0xe4 0xbd 0xa0 0xe5 0xa5 0xbd 0x00 wchar_tws[10] =L"你好";//內存中對應0x60 0x4f 0x00 0x00 0x7d 0x59 0x00 0x00 0x00 0x00 0x00 0x00 printf("Locale is: %sn", setlocale(LC_ALL,"zh_CN.UTF-8"));//Locale is: zh_CN.UTF-8printBytes(s,7);//0xe4 0xbd 0xa0 0xe5 0xa5 0xbd 0x00 printBytes((char*)ws,12);//0x60 0x4f 0x00 0x00 0x7d 0x59 0x00 0x00 0x00 0x00 0x00 0x00 printBytes((char*)str2wstr(s),12);//0x60 0x4f 0x00 0x00 0x7d 0x59 0x00 0x00 0x00 0x00 0x00 0x00 return(0);}

編譯后,執行結果如下:

Locale is: zh_CN.UTF-80xe40xbd0xa00xe50xa50xbd0x000x600x4f0x000x000x7d0x590x000x000x000x000x000x000x600x4f0x000x000x7d0x590x000x000x000x000x000x00

第二行輸出也印證了我們之前說的多字節字符串在內存中以UTF-8存儲,"0xe4 0xbd 0xa0 0xe5 0xa5 0xbd"正是"你好"的UTF-8編碼。

第三行輸出印證了之前說的寬字符串在內存中以Unicode存儲,"0x60 0x4f 0x00 0x00 0x7d 0x59 0x00 0x00"正好是寬字符串L"你好"對應的Unicode。

setlocale(LC_ALL, "zh_CN.UTF-8")設置locale,程序將以UTF-8解碼寬字符串。調用mbstowcs()后,可以看到“你好”的UTF-8編碼 "0xe4 0xbd 0xa0 0xe5 0xa5 0xbd 0x00"確實被轉換成了“你好”對應的Unicode "0x60 0x4f 0x00 0x00 0x7d 0x59 0x00 0x00 0x00 0x00 0x00 0x00"。

如果將setlocale(LC_ALL, "zh_CN.UTF-8")換成setlocale(LC_ALL, "en_US.iso88591 ");那么最后一行的輸出也就會不一樣。

需要更多點擊這里

總結

以上是生活随笔為你收集整理的c++ unicode转换中文_彻底弄懂UTF-8、Unicode、宽字符、locale的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 伊人网国产| 成人美女在线 | 天天狠天天透 | 久久精品—区二区三区舞蹈 | 超碰91在线观看 | 国产在线激情视频 | 一区成人 | 欧美一区二区免费电影 | www.日韩欧美 | 国产精品99精品无码视亚 | 欧美精品一级二级三级 | 青青久久国产 | 又黄又色的网站 | 国产不卡在线观看视频 | www.青青草| 91午夜精品 | 成人高清视频免费观看 | 免费污视频 | 日本h漫在线观看 | 亚洲性网 | 日韩国产在线观看 | 海角社区在线 | 日韩人妻精品一区二区三区视频 | 中文字幕第一页在线 | 亚洲无限av | 久久av无码精品人妻系列试探 | 久久丫精品国产亚洲av不卡 | 外国黄色录像 | 在线看片中文字幕 | www五月天com| 欧美xxxx83d| 国产卡一卡二 | 在线视频天堂 | 久久涩涩| 国产精品久久久不卡 | 麻豆福利影院 | 夜夜嗨影院 | 国产精品久久久久久久一区二区 | 国产尤物在线视频 | 91久久久精品 | 亚洲精品在线不卡 | 色婷婷电影网 | 久久字幕 | 亚洲一区二区三区免费 | 男女做爰真人视频直播 | 夜夜爱爱 | www日本在线 | 亚洲国内自拍 | 日韩av成人 | 成人91看片 | 波多野结衣中文字幕在线播放 | 天堂av电影在线观看 | 国产美女永久免费无遮挡 | 久草资源网| 538在线精品 | 中文字幕一区二区视频 | 大尺度一区二区 | 亚洲欧美综合一区 | 国产精品99久久久久久久久 | 一本大道久久久久精品嫩草 | 四月婷婷| 五月99久久婷婷国产综合亚洲 | 久久成年人视频 | 台湾av在线播放 | 狠狠干夜夜干 | 成年人小视频 | 成人av一区二区三区 | 久久久久久久亚洲av无码 | 高清在线一区二区 | 午夜激情久久久 | 色屁屁影院www国产高清麻豆 | 黄色靠逼视频 | 国产精品精品久久久 | 国产在线视频在线观看 | 在线免费av网站 | 日本乱偷人妻中文字幕在线 | 亚洲精品国产99 | 一级片视频在线观看 | 国产丰满大乳奶水在线视频 | 欧美性三级 | 国产青青操 | 久久精品国产精品亚洲色婷婷 | 久草视频在线观 | 在线观看的av | 国产强被迫伦姧在线观看无码 | 日本大尺度吃奶做爰视频 | 熟妇熟女乱妇乱女网站 | 亚洲精品手机在线 | 免费无码不卡视频在线观看 | 人妻互换一二三区激情视频 | 里番精品3d一二三区 | 亚洲精品综合精品自拍 | 亚洲码欧美码一区二区三区 | 国产亚洲精品精品国产亚洲综合 | 五月天狠狠干 | 超碰v | 成年人免费黄色 | 最新精品国产 | 亚洲大尺度网站 |