迷惑人的Windows字符和字符指针类型分类:C&C++ 发布时间:2010/2/26 16:14:45
本打算通过前面两篇文章的讲解,后来的系列就可以通过使用一些简单的,常用的API写一些示例程序的讲解进行,但是发现还有一个不得不先讲一讲的要点,Windows下和字符串操作有关的数据类型。我看留言中也有几位朋友提到了,那我就在这篇中讲它吧。不会很枯燥的,各位慢慢看下去就是了。
下面我罗列一些我们在Windows平台下编程经常使用到的和字符或字符串有关的数据类型。 char 和 wchar_t 这两个类型大家绝对不会陌生吧,一个是单字节的字符类型,一个是宽字节的字符类型(也就是Unicode字符)。 char c = 'b'; wcha_t wc = L'b'; 上面我就分别定义了2个变量c和wc ,相信第一个定义大家都看的懂,就是定一个字符变量c,其中保存了'b'这个字符。 那么第二个呢? 我相信还是很多人都看的懂,要是你看不懂也没关系,现在就告诉你,也是定义一个字符变量wc, 只不过这个字符变量是Unicode字符变量,用2个字节来保存一个字符,而上面的c这个字符变量只有一个字节来保存,那么在'b'前面的L又是什么意思呢,它就表示这里的'b'这个字符是一个Unicode字符,所以第二个定义的意思就是将L'b'这个Unicode字符保存到wc这个Unicode字符变量中。 如果我要定义一个字符数组怎么定义呢? 用分别用单字节的char和宽字节的wchar_t来定义就应该是: char c[10]; wchar_t wc[10]; 如果是要带初始化的字符数组的声明,我们来看看怎么写 char c[] = "beyondcode"; wchar_t wc[] = L"beyondcode"; 看到了吗,宽字节的操作其实和单字节的字符操作一样吧,只是在前面加上L表示是宽字节的字符或者字符串。 上面都是属于C/C++中的知识,并没有涉及太多Windows中的数据类型,那么各位朋友们在Windows编程中看到的满到处都是的 TCHAR,LPSTR, LPCSTR, LPWSTR, LPCWSTR, LPTSTR, LPCTSTR 这些数据类型又是怎么回事呢? 别急,我们一步一步的来,最后我会联系到那上面去的。 上面的你都知道或者是理解了的话,那我们继续,除了可以声明一个字符数组,我还可以定义一个字符指针变量来指向一个字符数组,当然这个字符数组可以是Unicode的宽字节字符数组,也可以是单字节字符数组,如下: char c[] = "hello beyondcode"; //定义一个字符数组 wchar_t wc[] = L"hello beyondcode"; //定义一个宽字节字符数组 char *p = c; //定义一个字符指针,指向刚才的字符数组 wchar_t *wp = wc; //定义一个宽字节字符指针,指向刚才的宽字节字符数组 这样之后,我就可以通过指针来改变刚才我们定义的2个数组,例如: wp[0] = L'H'; const char *p = c; const wchar_t *wp = wc; 上面将的都是C/C++的基础知识,有点啰嗦,为了照顾新手朋友们嘛,下面我们就来看看Windows是怎么定义它的数据类型的 首先,定义了CHAR, WCHAR的这2个字符数据类型,就是我们上面讨论的两个字符数据类型改了一下名字而已。现在你还不昏吧·· typedef char CHAR; typedef wchar_t WCHAR; 然后,用刚才定义的 CHAR, WCHAR这2个字符数据类型去定义了一系列其他字符指针类型。 typedef CHAR *LPSTR; typedef WCHAR *LPWSTR; 这样一定义之后,LPSTR的就是 CHAR*, 而CHAR 又是char, 所以LPSTR的本质就是 char*,也就是我们上面熟悉的不能再熟悉的字符指针, 那LPWSTR不用我推导,相信你也推导出来了吧。不过我还是推导一下,LPWSTR是 WCHAR * , WCHAR是wchar_t,这样LPWSTR就是 wchar_t* ,也就是我们上面讨论的宽字节字符指针。上面这些定义都是在WinNT.h这个头文件中定义的,读者朋友们有兴趣在这个头文件里面去挖掘挖掘吧,上面2个定义我只是提取了重要的部分,其实在里面他还定义了其他很多别名. 看了LPSTR, LPWSTR是怎么一回事之后,我们再接再厉,看看LPCSTR,LPCWSTR这2个数据类型又是怎么一回事呢, 老规矩,先看windows的定义。 typedef CONST CHAR *LPCSTR; typedef CONST WCHAR *LPCWSTR; 所以,在windows平台下的编程过程中,凡是可以使用char* 的地方,你都可以使用LPSTR来代替,凡是可以使用wchar_t*的地方,你都可以使用LPWSTR来代替,至于怎么用,还是那句老话,看你个人心情,只不过Windows的API函数中关于字符串的都是使用LP这种数据类型。但是你还是可以给他传递char* 或者 wchar_t* ,只要他们的本质是一样的,那怎么不可以呢~~ 下面,我们来看一看一些示例。 char c = 'c'; 和 CHAR c = 'c'; 是一样的 wchar_t wc = L'w'; 和 WCHAR wc = L'w'; 是一样的 char* p 和 LPSTR p 是一样的 wchar_t* wp 和 LPWSTR wp 是一样的 再来看看动态内存分配怎么写的呢 char* p = new char[10]; //动态分配了十个字符 CHAR* p = new CHAR[10]; LPSTR p = new CHAR[10]; LPSTR p = new char[10]; 宽字节的再来一次 wchar_t* wp = new wchar_t[10]; 也可以写成下面这些形式 WCHAR* wp = new WCHAR[10]; LPWSTR wp = new WCHAR[10]; LPWSTR wp = new wchar_t[10]; 通过上面这些,我想你大概已经了解了LPSTR, LPCSTR, LPWSTR, LPCWSTR这四个数据类型了,他们无非就是: LPSTR ------- char* LPCSTR ------- const char* LPWSTR ------- wchar_t* LPCWSTR -------- const wchar_t* #ifdef UNICODE typedef WCHAR TCHAR; #else typedef char TCHAR 看到了吗? 它也是根据UNICODE这个宏被定义没有,如果被定义了,那么TCHAR代表的数据类型就是WCHAR, 也就是wchar_t, 如果没被定义,那么TCHAR 就代表的是char 同样LPTSTR,LPCTSTR也是这样的,考虑到篇幅,我就只列出LPTSTR来给大家看看了 #ifdef UNICODE typedef LPWSTR LPTSTR; #else typedef LPSTR LPTSTR; TCHAR tc = 'a'; 或者是 TCHAR tc = L'a'; 是否合适呢? 前面我已经说过了字符或字符串常量前面加L代表这是宽字节的字符或字符串,将一个宽字节字符赋值给一个TCHAR数据类型的变量tc,什么情况下是正确的呢? 各位思考一下呢? 如果反过来,当前的工程是ASCII环境,那么TCHAR代表的是char这种数据类型,那么第一个赋值语句就是正确的,而第二个就是错误的了。 分析了这么多,我就是要讲一个宏 _T(), 只要将字符或者字符串常量放在_T()这个宏里面,那么这个宏就能根据当前的环境决定是否在字符或字符串前面加L,如下面: TCHAR tc = _T('A'); 如果这么写,在不需要改写源代码的情况下,就可以编译出Unicode和ASCII两套程序 而只需要改变工程的环境而已。 这篇文章的内容大概就这么多了,关于后续文章的内容安排,我会适当采纳各位朋友的留言来进行安排。 在这里我介绍的是Windows平台下的和字符串操作有关的数据类型,至于MFC中的CString类,c++标准库中的string,我就不做讲解了。 还有,前两篇的文章中我说微软定义这些数据类型为大写是为了编码的方便,不需要切换输入法,很多朋友都留言给我指出了,其实我是开了一个小玩笑,毕竟面对的是初学者,我觉得在目前这种环境下,没有必要给他们讲什么代码移植性啊,兼容性这些概念,那些在达到一定程度之后就会慢慢理解的,所以我自己想了一个小小的优点来说明那个问题,不过还是感谢你们的补充说明,谢谢·· |
|


最新评论