原文:http://www.cnblogs.com/cchyao/archive/2010/09/16/1827793.html
C++主要使用的是C-Style字符串,而M$在Windows中又增加了很多C-Style字符串的变体。这个一多嘛,就容易乱~
所谓字符串,就是由字符组合而成,所以我们先来将将字符类型。
首先,存在两种最基本的字符类型:char和wchar_t。char大家都很熟悉了,我就跳过。至于wchar_t,是应用于UNICODE的宽字符,即一个字符2Bytes,16Bits。事实上,Windows中利用
typedef unsigned short wchar_t
定义wchar_t
然后为了书写方便(MS我也没觉得有多大差别),M$又把那两个基本字符类型重新的给他typedef了一遍,即:
typedef char CHAR
typedef wchar_t WCHAR
为了使得兼容性更加,M$又定义了TCHAR数据类型:
#ifdef UNIOCDE
typedef WCHAR TCHAR
#else
typedef CHAR TCHAR
#end if
这样,你不用关心是要使用ANSI字符串还是Unicode,编译器会自动根据你的OS来选择。
然后,M$又利用上面的几种基本数据类型,定义了一些字符串指针类型。
LPSTR和LPCSTR:LPSTR是指向以0结尾的ANSI字符串的指针,后者是const指针
typedef CHAR* LPSTR
typedef const CHAR* LPCSTR
LPWSTR和LPCWSTR:LPWSTR是指向以0结尾的UNICODE字符串的指针,后者是const指针
typedef WCHAR* LPWSTR
typedef const WCHAR* LPCWSTR
同样,为了摆脱对ANSI还是UNICODE的选择麻烦,M$也增加了LPTSTR和LPCTSTR两个字符串指针类型。他们被如下定义:
typedef TCHAR* LPTSTR
#ifdef UNICODE
typedef LPSTR LPTSTR
#else
typedef LPWSTR LPTSTR
#endif
/////////////////////////////////////
typedef const TCHAR* LPCTSTR
#ifdef UNICODE
typedef LPCSTR LPCTSTR
#else
typedef LPCWSTR LPCTSTR
#endif
ps:你会在某些地方看到存在PSTR/PWSTR/PTSTR等等,与上面的只却一个L的字符串指针类型。实际上,这个是长指针和短指针问题。LPXX是长指针,PXX是短指针。不过在32Bit的系统上,二者已经没有区别。
然后说说两个比较成熟好用的字符串类型:String和CString
String是C++的标准字符串,需要string(不带.h)头文件和std名字空间支持。
CString是M$为MFC设计的字符串,功能更加强大,而且这玩意儿是安全的。需要atlstr.h文件和MFC DLL的支持。不过目前已经有人将此类型从MFC中分离~
为了增强程序的通用性,还必须注意以下几点:
1、既然程序里不能出现char,那表示字符串时,就不能再习惯性的用char*了。应该改为TCHAR*,或者是PTSTR。后一种是 windows的变量,类似的有:PSTR、PTSTR、LPTSTR、LPSTR、PCTSTR等等等等。这也是让人一开始接触会头大的地方。其实并非如此恐怖,我以PCTSTR为例做个解释:P代表指针(和LP是一个东西,LP的本意是Long Pointer,16位windows时代的遗留物。),C代表const,T代表TCHAR,STR代表字符串。所以PCTSTR其实就是const TCHAR* 的意思。而PSTR也就是char* 的意思。所以我们在表示字符串时也不能使用PSTR等不带T的变量类型名。
2、表示字符串常量时,不能简单的用双引号括起来,因为那代表ascii字符串。同样也不能在前面加L,因为那代表unicode。我们的程序要做到的是通用性,即不是ascii也不是unicode。所以我们在字符串前应该加的是TEXT,比如MessageBox(NULL,TEXT("Fypher"),TEXT("FF"),MB_OK)。TEXT还可用于字符。比如TCHAR m=TEXT('A');
3、TCHAR FF[50]。FF能装多少字符?哈!不要习惯性的sizeof(FF)了,应该_countof(FF)或者sizeof(FF)/sizeof(TCHAR)。因为我们不确定TCHAR到底是char 还是 wchar_t。
4、该和一堆老朋友说再见了……我们不能再使用以前的字符串处理函数或者字符处理函数了。比如strlen、strcat、strcmp等等等等……因为这些是ascii专用的,通通改成使用T家族的吧。前缀都换成_tcs。比如_tcslen、_tcscat、_tcscmp等等……顺便补充一下wcs前缀是wchar_t使用的。恩,还有大家用得超爽的sprintf,今后就改成_stprintf了吧~呵呵。补充:swprintf是 wchar_t它家的。对了,windows认为_tcscpy、_tcscat等不安全,所以使用这些函数编译器会报警。可以改用windows推出的 _tcscpy_s、_tcscat_s等“安全”函数,其实就是多了个参数用来指明缓冲区大小(记得用_countof哦~!^_^)。windows 还推出了形如StringCchCat的一套字符串处理函数,我没怎么用过。windows也有一个字符串比较函数CompareString。功能比 _tcscmp强大多了。比如可以设置忽略大小写等。
5、IsTextUnicode函数可以用过一系列统计学的方法判断某个字符串是不是unicode字符串。 MultiByteToWideChar和WideCharToMultiByte函数可实现Ascii和Unicode字符串的相互转化。这些的使用场合都不大。因为我们的程序应该做到“没有”ascii和unicode。
6、恩,虽然绝大多数情况下应该使用TCHAR,但是记住GetProcAdress这个特殊的函数吧,它的参数只能是char*。因为在导出函数表里函数名是用ascii码写的……
7、最后一点,记得要#include <tchar.h>哦!呵呵~ 由于windows内核采用的是UNICODE,UNICODE版的程序必然比ASCII版的程序效率高(比如不用在调用函数时在堆里分配空间把参数转成 UNICODE,然后再调用UNICODE版的函数),所以我们最好是在程序的开头加上#define UNICODE和#define _UNICODE,把程序转换成UNICODE版的。如果程序的字符串处理完全按照上面的通用性要求做了是不会出错的。
8、注意:str前缀与wcs前缀都是标准C函数,需要有标准C运行库才能够使用。而lstr前缀的是window提供的原生函数,不需标准C运行库。