C++中的字符串編碼處理方法

c++中的字符串編碼處理方法

今天由于在項目中用到一些與c++混合開發(fā)的東西 ,需要通過socket與c++那邊交換數(shù)據(jù),沒啥特別的,字節(jié)碼而已,兩邊確定一種編碼規(guī)則就行了。我們確定的utf-8。關(guān)于c++的 這種又是寬字節(jié) 又是messageboxw 又是messageboxa 的 ,說實話相比c#而言 搞的確實非常的和稀泥 搞的非常的糊,別說新手 有些不是新手的都搞不明白。

 

字符串字面量怎么被編碼成字節(jié)的

什么是字符串?c#里的 string?c++里的char* ? 字符串的本質(zhì)是什么?字符串不過是一個特殊的數(shù)據(jù)字節(jié)包裝 帶有編碼信息,特別是c++的 更原始 更便于我們想清楚這個底層,其實其他的已經(jīng)迎刃而解了。首先我們無論如何確定一個東西 那就是交換的東西是字節(jié)碼 ,說白了 也就是c++ 里的char [ ] 也就是char *,在我不管你編碼的情況下 我新建vc++項目 在代碼里這樣寫:

char str1[] = "中a";
printf("%s\r\n", str1);

能不能輸出東西?能不能輸出中文 當(dāng)然能,那這個str1 字節(jié)碼到底是什么字節(jié)碼, 只要我們把這個搞明白就可以了。一切未知的恐懼源于不明白。我們先調(diào)試c++代碼 取到字節(jié)碼,然后編寫下面這兩句c#代碼:

 byte[] bts2 = new byte[] { 0xd6, 0xd0, 0x61 };
console.writeline(encoding.getencoding("gb2312").getstring(bts2));

正常輸出了c++代碼里的中文 由此可見c++里默認(rèn)代碼到字節(jié) 的字面量轉(zhuǎn)換 就是gb2312 ,就這樣而已。就這樣而已 ,真的就這么點(diǎn)東西 ,不要探究是什么機(jī)制驅(qū)使vc++默認(rèn)把字符串轉(zhuǎn)換到了gb2312編碼,事情不要歪呀歪的想想復(fù)雜了,人的精力是有限的 要放在有作用的地方。你看c++里是char [ ] 還不像c#的string經(jīng)過包裝的 更便于你想明白這個過程。不是說c++有std庫么 不是有string 么 還沒講呢 ,c++這門語言呢又好又不好 設(shè)計特點(diǎn)是暴露的細(xì)節(jié)多 各個細(xì)節(jié)你都可以自己控制 讓會用的人知道自己在做什么 ,但是也有些坑,其實string 就是char[] 的變種而已。你看c++里 在你琢磨不透的情況下悄然在你不知情編碼的情況下轉(zhuǎn)換成了字節(jié)碼,c#的string 封裝的 不會給你這個機(jī)會 有明確的encoding庫調(diào)用指定編碼。

 

窄字符和寬字符 ,怎么個寬法

c++里字符串的字面量分為兩種 一種是普通的窄字符 ,也就是普通的char [ ] 一個元素占1字節(jié), 另一種是寬字符 wchar_t [ ] 一個元素占2字節(jié),_t("中a") 或者l"中a" 這種就是強(qiáng)行表示unicode寬字符字面量。 寬字符 怎么個寬法呢,我們說他是unicode 也就是utf-16,我們用c#進(jìn)行驗證:

 byte[] bts3 = new byte[] {  0x2d,0x4e, 0x61,0x00, };
console.writeline(encoding.unicode.getstring(bts3));

好了,這就明朗了,c++這玩意兒 由于歷史遺留原因,直接在代碼書寫字符串字面量搞了兩套標(biāo)準(zhǔn) 窄字符和寬字符 ,你看上面的同字符里面的字節(jié)碼整的兩套標(biāo)準(zhǔn) 這就很扯,整的被迫大多數(shù)c++的函數(shù) 或者接口都要按照這個套路玩。就有了看到的messageboxa ()接受char[]窄字符參數(shù),messageboxw()接受寬字符參數(shù) ,不要有誤區(qū)哈 覺得char[ ] 就不能輸出中文 ,能不能是由對應(yīng)的地方能不能解析這個字節(jié)碼決定的 而不是其他。

 

關(guān)于utf-8

utf-8的現(xiàn)實意義更大于編程的字面量意義 ,為什么這么說,現(xiàn)在網(wǎng)絡(luò) 數(shù)據(jù)交換都是utf-8 編碼,c++編程 字面量 沒有所謂utf-8這個說法 ,utf-8是一種落地編碼,落地編碼 懂嗎?就像圖像編程 保存最終格式有.jpg .png,utf-8 他是變長的 對于字符串處理會出現(xiàn)很多問題 不利于程序處理,圖像編程中不管你jpg png格式也好載入到內(nèi)存中最后都是易于處理的bmp內(nèi)存映像。編程中都是unicode因為2字節(jié)代表一個字符 標(biāo)標(biāo)準(zhǔn)準(zhǔn)的 是對齊的,利于編程處理。還有 utf-8 一個中文3字節(jié) 其實比utf-16 一個中文2字節(jié) 多, 但是如果是英文的話 就是1字節(jié) 可以實現(xiàn)unicode到ascii的無縫轉(zhuǎn)換 可以處理一些老舊系統(tǒng)的兼容問題。 c++里unicode可以通過手段轉(zhuǎn)換為utf-8:

void unicodetoutf8(const wchar_t* unicode,char  utf82[],int * lenout)
{
  int len;
  len = widechartomultibyte(cp_utf8, 0, unicode, -1, null, 0, null, null);
  char szutf82[50] = { 0 };
  *lenout = len;
  widechartomultibyte(cp_utf8, 0, unicode, -1, utf82, len, null, null);
}

 

關(guān)于vc++項目屬性里的設(shè)置字符集

什么意思呢:

當(dāng)選擇“使用unicode字符集”時,編譯器會增加宏定義——unicode;而選擇“使用多字節(jié)字符集”時,編譯器則不會增加宏定義——unicode。https://blog.csdn.net/huashuolin001/article/details/95620424
當(dāng)選用“使用unicode字符集”時,調(diào)用函數(shù)messagebox,實際使用的是messageboxw,messageboxw關(guān)于字符串的入?yún)㈩愋褪莑pcwstr,使用messagebox時,字符串前需加l::messagebox(null, l"這是一個測試程序!", l"title", mb_ok);

多字節(jié),默認(rèn)的窄字符char[]帶中文 就是典型的多字節(jié),接上面章節(jié)說明 多字節(jié)+中文 對于字符串處理分割 會帶來很多問題,所以帶中文請盡量使用寬字符。然后另一個 基于gb2312和unicode編碼我就不細(xì)說了哈,如果你想你的程序能夠賣到國外在世界范圍內(nèi)使用,那么請使用unicode,也就是 l" " 寬字符。c++里這些概念搞的比較糊 ,我描述的這些也是個意會 ,也許某些細(xì)節(jié)部分說錯了 像原來文章里那些評論里那樣 尖銳的指出來 不怕批評。

最后 ,一些測試的大雜燴代碼:

// consoleapplication1.cpp : 定義控制臺應(yīng)用程序的入口點(diǎn)。
//
#include "stdafx.h"
#include <iostream>
#include "h1.h"
#include "fqtabdata.h"
#include "test1.h"
#include <windows.h>
#include <string>
#include <iomanip>
#include <type_traits>
using namespace std;
//引用的使用方式
void test1(int &r){
  r = r+1;
}
void unicodetoutf8(const wchar_t* unicode,char  utf82[],int * lenout)
{
  int len;
  len = widechartomultibyte(cp_utf8, 0, unicode, -1, null, 0, null, null);
  char szutf82[50] = { 0 };
  *lenout = len;
  widechartomultibyte(cp_utf8, 0, unicode, -1, utf82, len, null, null);
}
int _tmain(int argc, _tchar* argv[])
{
  setlocale(lc_all, "");//注意控制臺輸出要先加上這句哈要不然無法輸出中文
  wchar_t wstr2[] = l"中a";
  wprintf(l"%ls\r\n", wstr2);
  char str1[] = "中ab";
  printf("%s\r\n", str1);
  return 0;
  //關(guān)于c++里的編碼問題
  //    并非 不在在項目屬性里設(shè)置編碼字符集 為unicode 就不能顯示中文
  //char str11[] = "中a";         printf("%s", str11);
  //這段代碼照樣顯示中文,中a被編譯器編成3個元素存在str11 里+\0結(jié)尾
  //當(dāng)選擇“使用unicode字符集”時,編譯器會增加宏定義——unicode;而選擇“使用多字節(jié)字符集”時,編譯器則不會增加宏定義——unicode。
  //https://blog.csdn.net/huashuolin001/article/details/95620424
  //當(dāng)選用“使用unicode字符集”時,調(diào)用函數(shù)messagebox,實際使用的是messageboxw,messageboxw關(guān)于字符串的入?yún)㈩愋褪莑pcwstr,
  //使用messagebox時,字符串前需加l
  //::messagebox(null, l"這是一個測試程序!", l"title", mb_ok);
  //關(guān)于這個l ,等同于_t("")  tchar 這些玩意兒他們都有同等意義
  //可以傻瓜的理解 l 本身就是搞一個寬字符型 字符串 ,每個字符占2字節(jié)
  //wchar_t ws[] = l"國家";
  //設(shè)置為unicode 就意味著寬字符 就意味著字符串 要加l
  //就像前面的 好多函數(shù)接口有兩種版本 messageboxa messageboxw ,
  //messageboxw就意味著你要傳一個寬字符數(shù)組進(jìn)去 也就是 wchar_t 或者l"dd"
  //注意多字節(jié)字符集是一個很容易讓人費(fèi)解的玩意兒,
  //我們說  utf-8是 一種unicode的落地編碼
  //編程里都是用 unicode 不管項目設(shè)沒設(shè)置unicode字符集 wchar_t ws[] = l"國家"; 得到的都是寬字符串
  //但是編程代碼里 沒有utf-8 這一說法 utf-8是變長的 也就是多字節(jié)   他是一種編碼落地
  //你想想你整個變長 別人接口怎么寫 ,怎么達(dá)到在讓你用變長省內(nèi)存的同時 識別你的有效字符
  //如果數(shù)組里存utf-8 你想想 別人要以字節(jié)數(shù)讀字符 半個的時候怎么搞
  //這跟gdi圖像處理是同一個道理 jpg png 各種是落地格式都可以讀進(jìn)來 但是到內(nèi)存都是bmp
  //還有不論哪種printf 或者其他接口 都不支持所謂的utf-8的參數(shù) 也沒這種接口可言
  //https://zhuanlan.zhihu.com/p/23190549
  //前幾天在微博上受到了@belleve給我的啟發(fā),于是簡單地實現(xiàn)了幾個在 windows
  //下接受 utf - 8 參數(shù)的 printf 系列函數(shù)。大致思路是判斷當(dāng)前 stdout / stderr
  //是否為控制臺,如果是控制臺則將參數(shù)轉(zhuǎn)為 utf - 16 后調(diào)用 wprintf 輸出,否則不轉(zhuǎn)換直接調(diào)用 printf。
  //l 是一個很微妙的 ,稱之為轉(zhuǎn)換為寬字符的字面量  什么叫字面量 根據(jù)你當(dāng)前編程環(huán)境 以及源代碼編碼 轉(zhuǎn)換成對應(yīng)的字節(jié)
  //l"發(fā)" 字面量 你細(xì)品
  setlocale(lc_all, "");
  printf("--------------------");
  //wchar_t wc = l'破';
  std::wstring wstr = l"破a的";
  std::cout << wstr.size() << std::endl;
  //utf-8 只是流行 ,事實上utf-8 一個漢字要占3字節(jié)  而utf-16一個漢字一字節(jié)
  /*wchar_t wstr2[] = l"破曉s";
  wprintf(l"%ls", wstr2);*/
  printf("--------------------//");
  char utf82[50] = { 0 };
  int len = 0;
  unicodetoutf8(wstr2, utf82, &len);
  //char* str222 = unicodetoutf8(wstr2);
  //printf("%s", str222);
  //printf("aaa");
  return 0;
  //
  //c++ 中指針的變種  引用的使用方式
  printf("aaa\r\n");
  int a = 123;
  int& b = a;
  a = 456;
  printf("%d \r\n", b);
  test1(b);
  printf("%d \r\n", b);
  int c = 345;
  test1(c);
  printf("%d \r\n", c);
  return 0;
}

關(guān)于c++中的字符串編碼處理的文章就介紹至此,更多相關(guān)c++字符串編碼內(nèi)容請搜索碩編程以前的文章,希望以后支持碩編程

下一節(jié):c語言完數(shù)的實現(xiàn)示例

c語言編程技術(shù)

相關(guān)文章
亚洲国产精品第一区二区,久久免费视频77,99V久久综合狠狠综合久久,国产免费久久九九免费视频