首先,介绍一个WINDOWS的字符集,WINDOWS所支持的字符集包括两种,多字节和宽字符(UNICODE),而在WIN2K及其以上内核中,都是使用宽字符来实现的,但也保留了多字节支持的API接口,这个实现的原理,其实是收到多字节后,把其转换为宽字符,再传下内核对象处理的。
还有一点需要说明,Mircosoft将COM从16位转换成32位时,规定了将需要字符串的方法只接受UNICODE字符串。
下面先介绍一下两个宏
运行时库头文件定义UNICODE环境的宏 UNICODE
Windows头文件定义UNICODE环境的宏 _UNICODE
Microsoft公司提供的C运行时库与ANSI标准C运行时库是一致的,而ANSI规定运行时库必须支持UNICODE和ANSI(多字节)字符串和字符,所以WINDOWS运行时库也是支持多字节和宽字符编码操作的两套接口的。
最典型的是 多字节接口:strlen,strcat,strcmp等,对应的宽字符接口:wcslen,wcscat,wcscmp等。
有了上面的基础,我们开始说到主题。
由于ARX环境是需要支持多个版本,而字符操作在ARX中是非常常见的,所以很近切的需要能解决既能在多字节环境编译又能在宽字符环境编译的代码。不用急,WINDOWS开发过程中也存在同样的问题的,所以,MICROSOFT是提供了解决方案的,关键就在TCHAR.H这个头文件中。
在TCHAR.H文件中,会根据_UNICODE宏是否定义来实现字符编码及其操作接口的自适应,如,在该文件中,对于CHAR的定义是这样的,当定义的_UNICODE宏是 typedef wchar_t TCHAR,当没有定义时 typedef char TCHAR,所以,当我们在定义字符串或字符时,只需要使用TCHAR来代替char,就能实现多字节与宽字符环境自适应的字符定义了。
定义后,我们关心的就是正确的给变量赋值了,在运行时库中,提供一个方法,当在某个字符串常量前加上大写L,则通知编译器,该字符串作为UNICODE字符串来编译,所以在TCHAR.H中也利用了这一点,来定义了随环境变化的通知编译器字符编码的机制。当定义了_UNICODE时,#define _TEXT(x) L##x,当没有定义时 #define _TEXT(x) x,这样只需要对每个常量字符串加上_TEXT()操作就可以自适应编译环境了。而在TCHAR.H中_TEXT又被定义成了更短,大名鼎鼎的_T了,所以,我们只需要对每个常量字符串加上_T()操作就可以自适应编译环境了。
另外一点,TCHAR.H中,也针对_UNICODE宏是否定义,实现了一套自适应编码环境的字符操作接口,所以建义在进行ARX编程时,如果需要多版本的支持,一定要使用TCHAR.H中定义的字符操用接口。
而且还需要说明的一点,MFC中的CString是随环境自适应的字符集,所以建义大家在编程过程中,尽量使用CString,而不是std::string。
最后把一常用需要注意的和代替的方法贴出来:
1.字符串类型尽量用CString
2.字符类型使用 TCHAR
3.字符串数组用 TCHAR[]
4.字符串指针用 TCHAR*
5.常量字符串指针用 const TCHAR*
6.字符串常量和字符常量加宏 _T
特别的:
1>CString::Format(_T("..."),...)//要加_T
2>LPTSTR 等等被多次嵌套定义过的宏尽量少用,用基础类型 const TCHAR*(或TCHAR*)替代;
3>为TCHAR*类型指针分配 N-1 个字符的空间: TCHAR* pbuffer = new TCHAR[ N*sizeof(TCHAR) ];
常用字符串函数,须使用支持Unicode/Ansi的宏函数替换前者:
Ansi字符串函数 Unicode/Ansi宏函数 功能说明
strcpy _tcscpy 字符串拷贝
strcat _tcscat 字符串连接
strlen _tcslen 求字符串长度
strcmp _tcscmp 字符串比较
atof _tcstod (注) 字符串转换为double
atoi _ttoi 字符串转换为int
注:上表中 _tcstod 和 atof用法不同,不能直接替换。
TCHAR与CString 互相转换
CString str = _T("你好");
char s[50];
s = (LPTSTR)(LPCTSTR)str;
str = (LPCTSTR)(LPSTR)s;
附上OBJECTARX每个版本对应的字符集:
OBJECTARX2007及其以上都是UNICODE(宽字符)编码。
OBJECTARX2007以下都是ANSI(多字节)编码。