读书笔记----《windows核心编程》第二章 Unicode与字符串处理

windows核心编程》第二章 Unicode与字符串处理

利用Unicode优点多多,比如与其他com组件的无缝连接,软件的本地化等等..

UNICODE(通常指UTF-16) ASCII  MBCS DBCS UTF-8 ,UTF-32区分;

UNICODE: 具体的详细说明,使用方法等信息可在MSDN中的Unicode and Character Sets 专栏中找到。大致说就是全球的所有符号都可以用2个字节进行唯一的编码,对于某些特殊国家(很少)可能2个字节无法满足所有的符号编码,则使用4个字节进行代理;

ASCII: 1个字节进行编码,最为常见(MSDNASCII codes可查看各个字符),

MBCS(Muti-Byte Character Set):

DBCS (Double-Byte Character Set):

MSDN中:

If _UNICODE is defined, the code will be compiled for UNICODE; if _MBCS is defined, the code will be compiled for DBCS (MBCS). The behavior if both symbols are defined is undefined.

VC++DBCS就是指MBCS,

ASCII码占用一个字节,准确的说,是7个比特(最后一位是奇偶检验位),由于汉字出现在ASCII码之后,所以汉字的编码必须与ASCII码兼容。还有一个问题就是,汉字的数目很多,用简单的一个字节根本无法表示,因此一个势在必行的方案就是用2个字节表达一个汉字,由于ASCII码占用7位的历史原因,所以这种聪明的编码方式规定:对于连续的2个字节,只有在2个字节的bit7都是1的情况下,才认为这2个字节合起来表示一个汉字,这种不同长度混排的编码方法通常叫做”MBCS”

                                                          ------《把脉VC++

其实”MBCS”并没有提供具体的编码方式和各国家语言的编码范围,这仅仅是一种方案:本国的文字过多,一个字节不能完全表示,所以用两个字节表示,同时兼容ASCII,仅此而已;所以亚洲的各个国家都有自己的编码规则:中国是GB2312(只包括简体中文)GBK(简体和繁体),日本是JIS编码;各个国家的编码互不兼容;

DBCSUnicode:

通过上边的内容应该已经知道了Unicode存在的必要性了,也应该能知道两者的区别;

当信息在国际间交流时,DBCS是无法在同一个文本中存储两种不同语言的,Unicode是完全可以的,Unicode为各个国家的每一个符号进行了全球唯一的编码;

                       --建议下载一份GB2312编码表和Unicode中文表比较看看;

UTF-8:

为什么会存在UTF-8 ?

设计UTF-8的本意是在网络传输数据时尽量将数据压到最少;美国国家的字符集合用ASCII码已经足够,但是Unicode编码将原本的一个字节扩大成两个字节,如‘A’在ASCII中为0x41(一个字节)Unicode中为0x0041(两个字节)这样就造成在网络传输中数据偏多(ASCII码的一倍),所以UTF-8应运而生;

UTF-80x0080以下的编码成一个字节(对于美国国家很适合),0x0080—0x07FFF之间的字符用两个字节表示(适合中东和欧洲国家),0x0800以上的使用三个字节表示(中国和其他东亚国家),最后代理对使用四个字节;

注意因为中文在UTF-8中占3个字节而在Unicode(UTF-16)中占2个字节,所以很多人都

认为在开发中应该使用Unicode而避免使用UTF-8,其实我觉得这得视情况而论,假如在数据中 英文与中文都存在的话Unicode并不会有很大优势,所以还得视情况而定;

UTF-32

全球所有的符号都有了唯一的定长的编码表示;在某些国家中(比如中国)由于符号过多,在Unicode中并没有为全部的中文定义为两个字节,部分生僻极少使用的使用代理定义为4个字节,UTF-8更是字符的长度不定,所以在想获取字符数的情况下还是有点忧虑(有杞人忧天的意思,虽然极少出现,但是理论上还是有可能),所以这时UTF-32就很有用,UTF-32将所有的符号定义为4个字节不存在任何代理对,完全表示全球的所有字符;但是由于4个字节的表示所以很少在保存文件或网络传输中使用,仅仅在应用程序内部使用;

ANSI字符 ()定义

char cBuffer = ‘A’;

char szText = “Hello World”;

Unicode字符()定义

wchar_t wcBuffer = L’A’;

wchar_t wszText = L”Hello World”;

一般写程序还是使用TCHAR类型和_T,_TEXT宏,编译器会在编译前判断是否定义了UNICODE(Project/Setting)而进行不同的宏展开;

//如果定义了UNICODE,就是一个16位字符;否则就是一个8位字符;

THCAR c = TEXT(“A”);

//如果定义了UNICODE,就是一个16数组;否则就是一个8位数组;

TCHAR szBuffer[100] = TEXT(“Hello World”);

Windows函数一般分为Unicode(CreateWindowW)ANSI(CreateWindowA),Window NT起,所有的window函数都由Unicode构建;调用ANSI版本的话函数在内部会进行ANSIUnicode的转换,然后调用Unicode版本,如果函数需要返回ANSI的字符串,则将结果由Unicode转换成ANSI然后返回,所以说调用ANSI版本的函数会产生时间和内存的开销;(C运行库中的Unicode版和ANSI版的函数都是独立实现的)

注意应用程序的资源(字符串资源,对话框模板资源,版本信息资源)exe文件中

储存的形式为Unicode形式;

为什么要放弃使用部分旧版本的字符串函数?

不建议使用的主要是修改,拷贝内存或字符串类型的函数,有代表性的是:strcpy,strcat,memcpy等等;这些函数的问题在于目标空间的内存需要修改或增加数据,但是函数本身并没有提供目标空间的大小,源空间的数据长度是未知的,可能长达数兆个字节,这样修改目标空间内存的话不是覆盖栈数据就是访问内存失败(内存不可写),导致整个应用程序失败!;

作为服务类应用程序的开发者更应该关注这个问题,因为这样的服务器会成为网络Hacker

的主要攻击目标,这种攻击方式就是"缓冲区溢出攻击";

#include 

#include 

int main()

{

int i = 9;

char buf[13];

memcpy(buf,"Hello World!\0\0\0\0H",17);

printf("---%d---%s---\n",i,buf);

return 0;

}

这只是一个缓冲区攻击的一个demo,函数将打印出i的值是72Hascii值)而不是9,这段代码仅仅在Debug环境下运行可打印出72,在Release环境下经过优化,ibuf的栈位置的距离会发生改变;demo仅仅是说说原理(原理不懂可参见<深入理解计算机系统>Bryant版本的相关章节);

特别要提到的是函数CompareString支持中文字符串的比较;

接下就是比较重要的两个函数WideCharToMultiByte和MultiByteToWideChar,两个函数分别可以用作Unicode(UTF-16)转向多字节编码(MBCS,UTF-8 UTF-7等等)和多字节编码转向Unicode(UTF-16);

void WriteStringToFile(LPCTSTR strFileInfo,LPCSTR strFilePath)

{

CStdioFile file;

if (!file.Open(strFilePath,CFile::modeWrite|CFile::modeCreate))

{

return;

}

file.WriteString(strFileInfo);

file.Close();

}

void WriteBytesToFile(BYTE *pByte,int nccbBytes,LPCSTR strFilePath)

{

FILE *pFile = fopen(strFilePath,"wb");

if (!pFile)

{

return;

}

fwrite(pByte,1,nccbBytes,pFile);

fclose(pFile);

}

void CTestDlg::OnButton1() 

{

// TODO: Add your control notification handler code here

char cMBCSBuffer[] = "中文ABC";

WriteStringToFile(cMBCSBuffer,"MBCS.txt");

wchar_t *pWideChar   = NULL;

char    *pUTF8Buffer = NULL;

int      nRequiredSize = 0;

int      nRet = 0;

__try

{

nRequiredSize = MultiByteToWideChar(CP_ACP,0,cMBCSBuffer,-1,NULL,0);

pWideChar = new wchar_t[nRequiredSize];

if (!pWideChar)

{

__leave;

}

nRet = MultiByteToWideChar(CP_ACP,0,cMBCSBuffer,-1,pWideChar,nRequiredSize);

if (nRet == 0)

{

__leave;

}

WriteBytesToFile((BYTE *)pWideChar,sizeof(wchar_t)*nRequiredSize,"Unicode.txt");

nRequiredSize = WideCharToMultiByte(CP_UTF8,0,pWideChar,-1,NULL,0,NULL,NULL);

pUTF8Buffer = new char[nRequiredSize];

if (!pUTF8Buffer)

{

__leave;

}

nRet = WideCharToMultiByte(CP_UTF8,0,pWideChar,-1,pUTF8Buffer,nRequiredSize,NULL,NULL);

if (nRet)

{

WriteBytesToFile((BYTE *)pUTF8Buffer,nRequiredSize,"UTF8.txt");

}

}

__finally{

if (pWideChar)

{

delete []pWideChar;

pWideChar = NULL;

}

if (pUTF8Buffer)

{

delete []pUTF8Buffer;

pUTF8Buffer = NULL;

}

}

return;

}

 

 

上述代码实现了MBCS  Unicode  UTF8的转换;

注意: char cMBCSBuffer[] = "中文ABC"; 为何这句就是用MBCS编码的呢?打开编译器Project/Setting/C/C++选项卡下面已预定义了_MBCS;MBCSASCII兼容;

你可能感兴趣的:(windows核心编程读书笔记)