*极力主张在程序中始终使用Unicode字符串:性能,本地化,同COM和.NET互相操作
1.字符编码
DBCS:双字节字符集:有的占1字节,有的占2字节!nightmare
UTF-16:每个字符都为2字节,最折衷,支持代理UTF-32,*Vista默认的Unicode
其他:
UTF-8:大小1字节到3字节不等,代理为4字节,流行的编码方式,但对大字符不如UTF-16高效。
UTF-32:都为4字节,不用代理,高效但内存占用多,一般在应用程序内部使用。
2.ANSI、Unicode与字符串数据类型
wchar_t:microsoft的c/c++编译器的内建数据类型(UTF-16),有编译器开关。
定义:wchar_t c = L'A';
wchar_t szBuffer[100] = L"A String";
WinNT.h定义的数据类型:
CHAR 8bit
PCHAR 指针
PSTR 字符串指针(CHAR)
PCSTR const字符串指针
------
WCHAR 16bit
PWCHAR
PWSTR
PCWSTR
------
(WinNT.h中的__nullterminated:头部注解,企业版VS的/analyze开关)
*使用WinNT.h定义的宏TCHAR PTCHAR PTSTR PCTSTR来兼容所有ANSI和Unicode字符串
3.Windows中的Unicode函数和ANSI函数
windows函数多数列表中有字符串,则通常有两个版本,functionW和functionA,在WinUser.h中function是个宏。
应避免使用ANSI版本的函数(bug和效率),ANSI函数会调用Unicode函数
*使用:#define UNICODE 来确定调用Unicode函数版本。
*VS中创建项目,默认#define UNICODE
*创建DLL可以考虑实现两个函数版本,参考WinUser.h
*不要使用只有ANSI版本的废弃函数(WinExec和OpenFile,CreateProcess和CreateFile INSTEAD)
*所有的COM都只用unicode
4.C运行库中的Unicode函数和ANSI函数
c运行库的Unicode函数和ANSI函数不会互相调用,所以没有效率影响。
*使用TChar.h定义的宏_tcslen,而不使用wcslen或strlen
*不是c++标准的标识符,c++运行库会加前缀_,所以,应确保同时定义#define UNICODE #define _UNICODE
*VS中创建项目,默认#define _UNICODE
*使用示例程序的CmnHdr.h
5.C运行库的安全字符串函数
使用StrSafe.h中的安全字符串函数来代替修改传入字符的字符串函数:strcpy wcscpy wcscat
目的:防止把大小为4的字符串放入大小为3的字符串中
*迁移到安全版本可能会遇到问题,比如_tcscpy_s和StringC*
---初识---
必须在包含所有其他文件后才包含StrSafe.h
安全的字符串函数后缀为_s,使用stdlib.h的_countof宏来计算字符数
错误处理:p19
检查errno_t值判断是否为S_OK:errno.h
errno_t result = _tcscopy_s(szBuffer, _coundof(szBuffer), TEXT("0123456789"));
*错误会清空szBuffer
---c运行库其他函数,获得更多控制---
StrCchCat ...
StringCbCat ...
*Cch使用_countof:字符数
*Cb使用sizeof:字节大小
返回HRESULT
*错误会截断szBuffer
*扩展版本,EX后缀:[p22]
---Windows字符串函数---
不赞成使用lstrcat和lstrcpy
使用ShlwApi.h定义的函数:对操作系统有关的数值进行格式化操作。
CompareString(Ex):需要以符合用户当地语言习惯的方式比较
CompareStringOrdinal:比较程序内部所用的字符串(路径,注册表项/值,XML元素/属性)
返回:宏 or result-2从而和c运行库一致。
6.为何用Unicode
本地化,exe/dll支持所有语言,效率高,占用少,调用未弃用函数,COM/.NET集成,容易操纵资源
7.推荐的字符和字符串处理方式
---字符准则---
使用通用数据类型:TCHAT/PTSTR
使用明确的数据类型:BYTE/PBYTE
用TEXT或_T宏来表示字面字符或字符串
注意:_countof和sizeof区别
注意:malloc(nCharacters*sizeof(TCHAR)); 而且出错编译器不会提供警告!
不要用printf转换ANSI和Unicode,而使用MultiByteToWideChar和WideCharToMultiByte
UNICODE和_UNICODE要同时指定。
---字符串处理函数准则---
使用后缀_s或前缀StringCch函数(控制截断和不控制截断)
使用CrtDefs.h定义的__STDC_WANT_SECURE_LIB__符号
用/GS编译器标志自动监测缓冲区溢出
不要用Kernel32的方法处理字符串,如lstrcat和lstrcpy
使用CompareString(Ex) CompareStringOrdinal比较字符串
8.Unicode和ANSI字符串转换
MultiByteToWideChar和WideCharToMultiByte [p27]
---导出ANSI和Unicode DLL函数代码模版---
[p29]
---判断文本是ANSI还是Unicode---
IsTextUnicode函数
该函数由AdvApi32.dll导出在WinBase.h中声明
*由于是根据内容猜测,有可能会不精确!