windows下宽字节和多字节的问题

宽字节和多字节,一度是我的噩梦,明明是调用同一个API,但是最后的返回值一会是char *,一会又是wchar_t *,实属烦人,前几天看吕鑫老师的视频,终于弄清楚了。

Windows中有两种编码格式:
(1) ANSI/多字节编码(每个字符占一个字节);
(2) UNICODE/宽字节编码(每个字符占两个字节)。
(ANSI是早期的编码格式,各国不统一,所以多种文字一起使用时经常出现乱码,后来为了统一编码格式,就出现了UNICODE,所以现在项目里默认编码一般都推荐使用UNICODE)

正因为上述原因,所以windows的IDE中很多API都有两种重定义格式:
#ifdef UNICODE
#define XXX XXXW //若编码格式为UNICODE,则使用宽字节形式API,后缀加上W
#else
#define XXX XXXA //若编码格式为ANSI,则使用多字节形式API,后缀加上A
#endif

那么问题也来了:
ANSI使用的字符串是多字节,类型定义为const char */LPCSTR;
UNICODE使用的字符串是宽字节,类型定义为const wchar_t */LPCWSTR;
假如项目代码中用到了很多的字符串操作,后面万一我想从ANSI码切换到UNICODE码,那么我的字符串格式肯定也要变了,我要把每一个LPCSTR都改成LPCWSTR吗?
或者我从UNICODE切换到ANSI,是不是也要把所有的字符串改掉?

为了省事,windows平台IDE给了L(X)宏和T(X)宏(头文件:#include <tchar.h>),作用如下:
(1) L(X):把字符串X全部转成宽字节;(这么做有风险,假如字符集是ANSI,那么使用L全部转成宽字节还是会报错)
(2) _T(X):这个宏不会明确指出到底是用ANSI还是UNICODE,它是根据API实际使用的字符集去自动转化编码,假如需要使用的字符串是多字节,它会把X自动转成多字节,同理,假如需要使用的字符串是宽字节,它会把X自动转成宽字节,比较方便,推荐使用这个宏。

此外,还有一种字符串定义方式TCHAR:
(1) Unicode模式下:TCHAR就是wchar_t;
(2) ANSI模式下:TCHAR就是char。
所以,在windows平台IDE中,最稳如老狗的字符串定义为: TCHAR *str = _T(“hello”);

综上所述,我相信很多人刚写MFC都碰到过这么一个问题:MFC的CString字符串怎么转化成C语言/C++自带的const char *类型字符串?
网上很多代码都是类似于以下代码写的:

CString str = _T("Hello world!");
const char *msg = str.GetBuffer();

我把这代码直接复制粘贴下来,但是我相信很多人又碰到了跟我一样的问题:这个代码,有时可以编译通过,有时编译却又通不过(肯定不止我一个人碰到这个事吧),但凡是做过项目开发的都应该有这个意识,这代码肯定是有问题的。。。。其实就是字符集在捣鬼。因为CString类的GetBuffer()方法,返回的字符串类型就是会根据字符集自动转换成char *(ANSI码格式)和wchar_t *(UNICODE码格式),所以上面两行代码在ANSI码格式下不会报错,因为它返回的是char *多字节字符串,但是在UNICODE码格式下肯定会报错,因为此时它返回的是wchar_t *宽字节字符串,下面这么写就比较稳妥:

CString str = _T("Hello world!");
const char *msg = (char *)str.GetBuffer();//即使返回值是wchar_t *宽字节字符串,手动强制转换成char *

当然了,如果不嫌麻烦,最最最稳如老狗的方法还是我在上面说的TCHAR *类型字符串:

CString str = _T("Hello world!");
TCHAR *msg = str.GetBuffer();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章