小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

C 之編碼問(wèn)題(Unicode,ASCII,本地默認(rèn))

 蘭亭文藝 2019-12-14

本篇文章試圖回答的問(wèn)題:

1、char* pStr='我aa';這句代碼執(zhí)行后,pStr指向的內(nèi)存區(qū)域中存儲(chǔ)的字節(jié)到底是根據(jù)什么碼表而來(lái)的呢?該字符串占幾個(gè)字節(jié)?

2、將一個(gè)VS2010的Windows程序設(shè)置了“使用Unicode字符集”到底意味著什么?

3、現(xiàn)在有一個(gè)文件,其存儲(chǔ)內(nèi)容未知(可能是文本,可能是圖像,可能是視頻),要求是:在文件最前面插入一串Unicode文本,插入完成后以文本程序打開(kāi)該文件,插入的文本不會(huì)顯示為亂碼(該文件本身的內(nèi)容不考慮)?!绾巫龅??

本人能力、精力有限,所言所感都基于自身的實(shí)踐和有限的閱讀、查閱,如有錯(cuò)誤,歡迎拍磚,敬請(qǐng)賜教——博客園:錢(qián)智慧。

一:

用VS2010新建一個(gè)win32控制臺(tái)應(yīng)用程序TestChar,代碼如下:

#include <iostream>
using namespace std;
int main()
{
    char* pStr="a";
    cout<<sizeof("a")<<endl;
    cout<<hex<<pStr[0]-0;
    cout<<pStr[1]-0<<endl;
    return 0;
}

打印結(jié)果如下:分析:存儲(chǔ)介質(zhì)(內(nèi)存、外存等)上存儲(chǔ)的都是二進(jìn)制數(shù)據(jù),而對(duì)于字符信息的存儲(chǔ),先查碼表進(jìn)行解碼,再把碼以二進(jìn)制信息存儲(chǔ),即pStr指向的這段內(nèi)存中存儲(chǔ)的都是字符們的編碼:一個(gè)中文字符,一個(gè)英文字母,一個(gè)全角字母。要得到”我“的編碼,默認(rèn)會(huì)查找本地碼表,本人是中文Win7系統(tǒng),查找的是GB2312碼表,而對(duì)照GB2312碼表可發(fā)現(xiàn),'我'的編碼正是ced2,與打印一致(f是符號(hào)位,可無(wú)視)。另外GB2312是不會(huì)對(duì)英文字母進(jìn)行編碼的,因?yàn)橛⑽淖帜笇儆诎虢亲址?,這類(lèi)編碼由ASCII碼表負(fù)責(zé),GB2312中的任何字符都占用兩個(gè)字節(jié),空字符也由ASCII負(fù)責(zé)編碼,這就是為何上面的字符串占用的字節(jié)數(shù)目是6。可見(jiàn),上面一句代碼,其實(shí)涉及到了兩張碼表:ASCII碼表和GB2312。二:新建一個(gè)MFC對(duì)話(huà)框程序,名為T(mén)estUnicodeChar。默認(rèn)情況下,VS2010建的項(xiàng)目都是基于Unicode的,即打開(kāi)項(xiàng)目的屬性,在”字符集“設(shè)置中都是”使用Unicode字符集“,這到底是什么意思呢?莫非在程序中用的中文都是以Unicode字節(jié)進(jìn)行存儲(chǔ)的?由上面的TestChar程序可以看出并非如此,pStr中的'我”是以GB2312進(jìn)行存儲(chǔ)的。又或者,源文件(h文件、cpp文件等)在磁盤(pán)上是以Unicode進(jìn)行編碼存儲(chǔ)的?也不是,源文件存儲(chǔ)默認(rèn)也是以本地GB2312進(jìn)行存儲(chǔ)的。驗(yàn)證方式:用UE編輯器隨便打開(kāi)一個(gè)設(shè)置了“使用Unicode字符集”項(xiàng)目的某個(gè)源文件,比如打開(kāi)本項(xiàng)目中的TestUnicodeCharDlg.cpp文件,在UE中以16進(jìn)制的形式查看該文件內(nèi)容,可以發(fā)現(xiàn)其前兩個(gè)字節(jié)并非FF FE(這是Unicode文件的標(biāo)識(shí)),你隨便找一個(gè)中文,對(duì)照其16進(jìn)制找到其編碼,然后跟GB2312碼表中的該中文的編碼對(duì)照即可驗(yàn)證。這是一個(gè)GB2312碼表的網(wǎng)頁(yè)鏈接:http://tool./gb2312tbl.php 我們知道,在C++中,有char和string,為了支持Unicode字符,還有wchar_t和wstring,我們可以認(rèn)為string是基于char的,而wstring是基于wchar_t的。為什么要引入U(xiǎn)nicode呢,只用char和string難道不能保存含有中文的字符(串)嗎?由TestChar程序,我們知道完全可以,并且采用的是GB2312編碼,問(wèn)題是你無(wú)法確定一個(gè)類(lèi)似pStr的混合串的字符數(shù)目,比如:string str='我a',你調(diào)用string的length方法不能準(zhǔn)確得到str的長(zhǎng)度,這給編程帶來(lái)了不便。所以你可以選用wstring和wchar:wstring wstr=L'我a',這時(shí)你再調(diào)用wstring的length方法就能準(zhǔn)確得到了,其中L前綴可以使后面緊跟的字符串解釋成寬字符串(Unicode)。因?yàn)閁nicode對(duì)任何字符都采用2個(gè)字節(jié)進(jìn)行編碼,所以length的實(shí)現(xiàn)想必也很簡(jiǎn)單:每?jī)蓚€(gè)字節(jié)算一個(gè)字符,進(jìn)而可以方便得到字符串的長(zhǎng)度,這便是Unicode優(yōu)于多字節(jié)編碼的地方:試想,如果采用多字節(jié)編碼,那么要實(shí)現(xiàn)基于這種編碼的字符串類(lèi)的length方法會(huì)非常頭疼。Unicode浪費(fèi)了存儲(chǔ)空間但帶來(lái)了編程上的簡(jiǎn)便。(關(guān)于這方面的詳細(xì)內(nèi)容可以參考《Windows程序設(shè)計(jì) 第5版》第1章)在Windows中,有這樣一些宏:_T,TEXT,TCHAR,CString,它們根據(jù)不同的設(shè)定有不同的含義。先看一下它們的使用:在TestUnicodeCharDlg.cpp的OnPaint方法中加上如下代碼:1 TCHAR * pStr=TEXT('a我');//_T與TEXT的含義是一樣的2 CString str1=TEXT('a我');3 CString str2=L'a我';View Code如果程序定義了UNICODE宏,則_T和TEXT(二者含義和用法完全一樣)便會(huì)把括號(hào)內(nèi)的字符串解釋為UNICODE字符串,TCHAR便會(huì)替換為wchar_t,CString便會(huì)替換為CStringW,否則(即沒(méi)有定義UNICODE宏),都會(huì)解釋為相應(yīng)的char版本。而L前綴不是宏,類(lèi)似強(qiáng)轉(zhuǎn):不管有沒(méi)有定義UNICODE宏,都把后面的字符串解釋為UNICODE字符串。而設(shè)置“使用UNICODE字符集”就相當(dāng)于定義UNICODE宏,即該設(shè)置僅僅是影響了一些宏的行為。若把該項(xiàng)目的“使用Unicode字符集”設(shè)置改為“未使用”,則編譯會(huì)出錯(cuò),因?yàn)榇藭r(shí)str2就是一個(gè)CStringA實(shí)例,你不能把一個(gè)L前綴的字符串(Unicode字符串)賦值給它。三:第三個(gè)問(wèn)題本質(zhì)上就是往一個(gè)文件中寫(xiě)Unicode字符串的問(wèn)題。涉及到編碼問(wèn)題的文件操作始終牢記一點(diǎn):以什么編碼寫(xiě),就以編碼讀。在TestUnicodeChar程序的OnInitDialog函數(shù)中加入如下代碼:1 BOOL CTestUnicodeCharDlg::OnInitDialog() 2 { 3 CDialogEx::OnInitDialog(); 4 5 // 將“關(guān)于...”菜單項(xiàng)添加到系統(tǒng)菜單中。 6 7 // IDM_ABOUTBOX 必須在系統(tǒng)命令范圍內(nèi)。 8 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 9 ASSERT(IDM_ABOUTBOX < 0xF000);10 11 CMenu* pSysMenu = GetSystemMenu(FALSE);12 if (pSysMenu != NULL)13 {14 BOOL bNameValid;15 CString strAboutMenu;16 bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);17 ASSERT(bNameValid);18 if (!strAboutMenu.IsEmpty())19 {20 pSysMenu->AppendMenu(MF_SEPARATOR);21 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);22 }23 }24 25 // 設(shè)置此對(duì)話(huà)框的圖標(biāo)。當(dāng)應(yīng)用程序主窗口不是對(duì)話(huà)框時(shí),框架將自動(dòng)26 // 執(zhí)行此操作27 SetIcon(m_hIcon, TRUE); // 設(shè)置大圖標(biāo)28 SetIcon(m_hIcon, FALSE); // 設(shè)置小圖標(biāo)29 30 // TODO: 在此添加額外的初始化代碼31 CFile myFile;32 33 34 if ( myFile.Open( _T('c:\\myfile.txt'), CFile::modeCreate | 35 CFile::modeReadWrite ) )36 {37 38 CString str=TEXT('a我');39 //myFile.Write('\xff\xfe',2);40 myFile.Write( str, str.GetLength()*sizeof(TCHAR) ); 41 myFile.Flush();42 }43 44 45 return TRUE; // 除非將焦點(diǎn)設(shè)置到控件,否則返回 TRUE46 }View Code運(yùn)行程序,然后用寫(xiě)字板、記事本、NotePad++、UE(UEdit)分別打開(kāi)mfile.txt發(fā)現(xiàn),有的能正常顯示,有的則亂碼。要知道,你往myfile.txt寫(xiě)進(jìn)去的是 兩個(gè)字符的Unicode編碼,用某文本程序去打開(kāi)myfile.txt,倘若該程序默認(rèn)情況下讀取文本時(shí)是按Unicode來(lái)解析的,則不會(huì)亂碼,否則就亂碼。我們把注釋的那行代碼的注釋拿掉,用任何支持Unicode的文本程序去打開(kāi)myfile.txt就不會(huì)出錯(cuò)了,因?yàn)橐粋€(gè)文本中的前兩個(gè)字節(jié)FF FE便向試圖打開(kāi)該文本的程序表明該文本應(yīng)該用Unicode進(jìn)行解析(你可以用NotePad++新建幾個(gè)Unicode格式的文本,隨便保存幾個(gè)字符,然后用UE以16進(jìn)制格式查看便可知Unicode文本的前兩個(gè)字節(jié)都是FF FE)。另外,經(jīng)常遇到有人問(wèn)這樣的問(wèn)題:CString如何轉(zhuǎn)換為char*?問(wèn)這個(gè)問(wèn)題之前,最好問(wèn)下自己:我的目的是什么,為何要進(jìn)行這樣的轉(zhuǎn)換,當(dāng)前項(xiàng)目有沒(méi)有設(shè)置Unicode。要知道,如果設(shè)置了Unicode,則CString存儲(chǔ)的是Unicode字符串,轉(zhuǎn)換為char*后,你如果直接顯示這個(gè)char*或者寫(xiě)到文件中(沒(méi)有把FF FE寫(xiě)到文件開(kāi)始處)然后打開(kāi),則會(huì)(假如打開(kāi)文件的程序默認(rèn)不以Unicode進(jìn)行解析)出現(xiàn)亂碼,所以,這種情況下,轉(zhuǎn)換為char*的意義不大——這不是說(shuō)不能把Unicode串轉(zhuǎn)為char*,這完全是可行的,本質(zhì)上這只是在把一個(gè)Unicode字符串的內(nèi)存內(nèi)容'活生生”取出來(lái)而已。不管怎樣,下面的代碼重新修改了OnInitDialog函數(shù),演示了幾種情況: 1 BOOL CTestUnicodeCharMFCDlg::OnInitDialog() 2 { 3 CDialogEx::OnInitDialog(); 4 5 // 將“關(guān)于...”菜單項(xiàng)添加到系統(tǒng)菜單中。 6 7 // IDM_ABOUTBOX 必須在系統(tǒng)命令范圍內(nèi)。 8 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 9 ASSERT(IDM_ABOUTBOX < 0xF000);10 11 CMenu* pSysMenu = GetSystemMenu(FALSE);12 if (pSysMenu != NULL)13 {14 BOOL bNameValid;15 CString strAboutMenu;16 bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);17 ASSERT(bNameValid);18 if (!strAboutMenu.IsEmpty())19 {20 pSysMenu->AppendMenu(MF_SEPARATOR);21 pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);22 }23 }24 25 // 設(shè)置此對(duì)話(huà)框的圖標(biāo)。當(dāng)應(yīng)用程序主窗口不是對(duì)話(huà)框時(shí),框架將自動(dòng)26 // 執(zhí)行此操作27 SetIcon(m_hIcon, TRUE); // 設(shè)置大圖標(biāo)28 SetIcon(m_hIcon, FALSE); // 設(shè)置小圖標(biāo)29 30 // TODO: 在此添加額外的初始化代碼31 CFile myFileW,myFileA,myFileCharArrow,myFileWOrA;32 33 34 if ( myFileW.Open( _T('c:\\myfileW.txt'), CFile::modeCreate | 35 CFile::modeReadWrite ) && 36 myFileA.Open( _T('c:\\myfileA.txt'), CFile::modeCreate | 37 CFile::modeReadWrite ) &&38 myFileCharArrow.Open( _T('c:\\myfileCharArrow.txt'), CFile::modeCreate | 39 CFile::modeReadWrite ) &&40 myFileWOrA.Open( _T('c:\\myFileWOrA.txt'), CFile::modeCreate | 41 CFile::modeReadWrite ))42 {43 44 CString strW=TEXT('a我');//因?yàn)楸卷?xiàng)目設(shè)置了Unicode字符集,所以我們知道CString會(huì)被替換為CStringW45 46 CStringA strA(strW);47 48 49 myFileW.Write( strW, strW.GetLength()*2); 50 myFileW.Flush();51 52 myFileA.Write(strA,strA.GetLength());53 myFileA.Flush();54 //CString的GetString返回的const類(lèi)型指針,要么在右邊強(qiáng)轉(zhuǎn),要么左邊用const類(lèi)型的char*去接55 //注意指針命名:p是pointer,c是const,如果有t則是TEXT,w是wide,l是long56 char* pstr=(char*)strA.GetString();57 /*下面這行代碼若不注掉,會(huì)報(bào)錯(cuò),因?yàn)楸境绦蚴荱nicode程序,58 strW會(huì)是一個(gè)CStringW類(lèi)型的字符串,它的GetString返回的是LPCWSTR類(lèi)型指針59 當(dāng)然不能賦值給LPCSTR類(lèi)型指針了,一個(gè)是const wchar_t*,另一個(gè)是const char*60 */61 //const char* pcstr1=strW.GetString();62 63 myFileCharArrow.Write(pstr,strlen(pstr));64 myFileCharArrow.Flush();65 66 //假設(shè)我們?cè)诰幊讨?,不知道有沒(méi)有使用Unicode設(shè)置,為了通用,我們可以盡量使用宏及通用版本的相關(guān)函數(shù)(如_tcslen)67 CString strWOrA=TEXT('a我');68 //注意這里的TCHAR不一定就是wchar_t,這取決于程序是否設(shè)置了Unicode69 const TCHAR* pctstr=strWOrA.GetString();//CString的GetString返回的是const指針70 myFileWOrA.Write(ptstr,_tcslen(pctstr)*sizeof(TCHAR));71 myFileWOrA.Flush();72 73 }74 75 76 return TRUE; // 除非將焦點(diǎn)設(shè)置到控件,否則返回 TRUE77 }View Code用UE察看幾個(gè)文件的內(nèi)容,如圖:其中,CED2是”我“的GB2312編碼,6211(注意字節(jié)高低次序)是”我“的Unicode編碼,我們可知,CStringA strA(strW)這行代碼,一定進(jìn)行了碼表間的轉(zhuǎn)換。結(jié)合代碼,文件內(nèi)容應(yīng)該不難理解。還有些讓人容易頭暈的字符串指針宏,下面列舉出來(lái):關(guān)于char*的:LPCSTR: long pointer const string,可看成const char*,與PCSTR相似LPSTR:可看成char*,與PSTR相似關(guān)于wchar_t*的:LPCWSTR,PCWSTR,LPWSTR,PWSTR通用版本(根據(jù)是否配置了Unicode有不同的宏替換):TCHAR*LPTSTR,LPCTSTR (T有點(diǎn)類(lèi)似TEXT宏的意思)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀(guān)點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多