vc中常见字符类型的讨论

来源:互联网 发布:三国群英传3 mac版 编辑:程序博客网 时间:2024/06/05 00:51

一、将要讨论的问题

char

wchar_t

TCHAR

_TCHAR

_T

_TEXT

__T

LPSTR  

LPCSTR  

LPCTSTR  

LPWSTR  

CString

 

 

二、一切的基础

首先,char就不说了,单个字节表示,ansi的方式

wchar_t是Unicode字符的数据类型,宽字符,用两个字节表示,它实际定义在<string.h>里:

 typedef unsigned short wchar_t;

我们都知道,在一个工程的属性中有一个选项:

Character set-----àUse UnicodeCharacter set   or    Use Multi-Byte Character set

它让你在以UNNICODE或MBCS的方式来使用字节

如果选了Use Unicode Character set,也就是说定义了宏:

#define UNICODE

如果Use  Multi-Byte Character set,也就是没有定义宏:

#define UNICODE,而定义了宏_MBCS

这是有很大区别的,直接造成了使用字符处理函数等多方面的差异。

尤其是在界面编程时,如果想考虑可移植性(即可在ansi下用,由可在Unicode下用),那么方法一:写两套代码,全部用宏的方式注释开,然后使用预处理,决定是使用Unicode还是MBCS。

方式二:和方式一一样,只不过编译器替我们做了这些,这就是TCHAR、TEXT、_T等一些列宏。

 

 

三、TCHAR及ANSI、UNICODE兼容性

TCHAR是定义在其中的一个宏,它视你是否定义了_UNICODE宏而定义成char或者wchar_t。

#ifdef UNICODE
typedef wchar_t TCHAR;
  #else
  typedef char TCHAR;
  #endif


如果你使用了TCHAR,那么就不应该使用ANSI的strXXX函数或者Unicode的wcsXXX函数了,而必须使用TChar.h中定义的_tcsXXX函数。另外,为了解决刚才提到带“L”的问题,TChar.h中定义了一个宏:“_TEXT”。

 以strcpy函数为例子,总结一下:
 .如果你想使用ANSI字符串,那么请使用这一套写法:
 char szString[100];
 strcpy(szString,"test");
 .如果你想使用Unicode字符串,那么请使用这一套:
 wchar_t szString[100];
 wcscpy(szString,L"test");
 .如果你想通过定义_UNICODE宏,而编译ANSI或者Unicode字符串代码:
 TCHAR szString[100];
 _tcscpy(szString,_TEXT("test"));

这样就很清楚了,还要注意一点是_TEXT这个宏

源码是这样的:

#define TEXT(quote) __TEXT(quote)   // r_winnt

如果定义了UNICODE,那么,#define __TEXT(quote) L##quote 

如果没有定义UNICODE,那么,#define __TEXT(quote) quote         // r_winnt

#define _T(x)       __T(x)

#define _TEXT(x)    __T(x)

如果定义了UNICODE,那么#define __T(x)      L ## x

如果没有定义UNICODE,那么#define __T(x)       x

很清楚了吧,本质上,_T   TEXT   _TEXT 这三个宏都是 __T 或者  __TEXT, 而后二者视情况决定在x前是否加上宏L

宏 L 表示将ANSI字符串转换成unicode的字符串,就是每个字符占用两个字节。

综上所述:当既想在ANSI上用,又想在UNICODE上用时,应该使用TCHAR来定义,然后使用_tcsXXX的函数,将字符串常量用TEXT等宏预处理。

 

四、常见基本字符类型及他们的引申宏定义在MBCS和UNICODE的指向:

Type

MBCS

Unicode

注释

TCHAR

char

wchar_t

映射宏,当定义UNICODE时,TCHAR映射到 wchar_t,否则,那么它映射到 char

_T

_TEXT

TEXT

__T

__TEXT

char

wchar_t

ASCII模式下,它们被忽略,也就是说被预处理器删除掉,但是如果定义了UNICODE,   则它们会将常量字符串转换成等价的   UNICODE

LPTSTR

TCHAR*

(实质上char*)

TCHAR*

(实质上wchar_t*)

 

LPCTSTR

const  TCHAR*

(实质上const char*)

const  TCHAR*

(实质上const wchar_t*)

 

WCHAR

wchar_t

wchar_t

始终是wchar_t

CHAR

char

char

始终是char

LPSTR

char*

char*

始终是char*

LPCSTR     

const char*

const char*

始终是const char*

LPWSTR

wchar_t*   

wchar_t*   

始终是wchar_t*   

LPCWSTR

const wchar_t*

const wchar_t*

始终是const wchar_t*

 

 

 

 

 

C表示const

W表示宽字符

T表示TCHAR,可移植

LP 指针

 

五、CString

MFC中封装了CString类,让很多初用MFC的人暗爽….但是久了会发现,CString和上述的多种类型转换、或者上述类型之间相互转换起来确实不方便,容易搞晕。

 

CString是封装了TCHAR,因此将编译条件从MBCS改为UNICODE(或者反过来时)都不需要修改代码,这就是TCHAR这个宏定义当初被引入的初衷。

构造CString对象的时候,会使用TCHAR数据类型,也就是说内部是根据编译条件(MBCS或UNICODE)将初始化数据转换为char或wchar_t的。

 

很多喜欢在MFC下编程的人一开始很喜欢CString,因为微软把他的基础功能封装的挺不错,不用去管理内存和使用指针。但是它还是有很多问题的,比如滥用operator操作使得内存拷贝越界,不过他的CopyBeforeWrite技术还是不错的,另外,他和stl的vector一样,使用了动态增加空间的方法。具体内部剖析:

http://blog.csdn.net/zp373860147/article/details/6968853

 

 

六、一些转换

话说现在,大部分程序开发会是在Unicode编译条件下进行吧。

那么char*和宽字符的互相转换就比较常用了。

1、 Unicode下CString转为char*:

方法一:使用API:WideCharToMultiByte进行转换

CString str = _T("你好world");

//注意:以下n和len的值大小不同,n是按字符计算的,len是按字节计算的
int n = str.GetLength();     // n = 7, len = 9

//获取宽字节字符的大小,大小是按字节计算的
int len = WideCharToMultiByte(CP_ACP,0,str,str.GetLength(),NULL,0,NULL,NULL);

//为多字节字符数组申请空间,数组大小为按字节计算的宽字节字节大小
char * pFileName = new char[len+1];   //以字节为单位

//宽字节编码转换成多字节编码
WideCharToMultiByte(CP_ACP,0,str,str.GetLength(),pFileName,len,NULL,NULL);

pFileName[len+1] = '\0';   //多字节字符以'\0'结束

 

方法二:使用函数:T2A、W2A

(ATL中的函数,使用USES_CONVERSION一定要小心,它们从堆栈上分配内存,直到调用它的函数返回,该内存不会被释放。如果在一个循环中,这个宏被反复调用几万次,将不可避免的产生stackoverflow。在一个函数的循环体中使用A2W等字符转换宏可能引起栈溢出。)

CString str = _T("你好world ");

//声明标识符
 USES_CONVERSION;

//调用函数,T2A和W2A均支持ATL和MFC中的字符转换
char * pFileName = T2A(str);  
//char * pFileName = W2A(str);//也可实现转换

//注意:有时候可能还需要添加引用#include   <afxpriv.h>

 

 

2、Unicode下char *转换为CString

方法一:使用API:MultiByteToWideChar进行转换

char * pFileName = "你好world";

//计算char *数组大小,以字节为单位,一个汉字占两个字节
int charLen = strlen(pFileName);

//计算多字节字符的大小,按字符计算。
int len = MultiByteToWideChar(CP_ACP,0,pFileName,charLen,NULL,0);

//为宽字节字符数组申请空间,数组大小为按字节计算的多字节字符大小
TCHAR *buf = new TCHAR[len + 1];

//多字节编码转换成宽字节编码
MultiByteToWideChar(CP_ACP,0,pFileName,charLen,buf,len);

buf[len] = '\0'; //添加字符串结尾,注意不是len+1

//将TCHAR数组转换为CString
CString pWideChar;
pWideChar.Append(buf);

//删除缓冲区
delete []buf;

方法二:使用函数:A2T、A2W

char * pFileName = "你好world";

USES_CONVERSION;
CString s = A2T(pFileName);

//CString s = A2W(pFileName);

方法三:使用_T宏,将字符串转换为宽字符

//多字节字符集,在vc6和vc7种可以编译通过的语句,但VS2005不能通过,默认为Unicode字符集
//AfxMessageBox("加载数据失败",0);

//书写代码使用TEXT("")或_T(""),文本在UNICODE和非UNICODE程序里都通用
AfxMessageBox(_T("加载数据失败"),0); 

//注意:直接转换在基于MBCS的工程可以,但在基于Unicode字符集的工程中直接转换是//不可行的,CString会以Unicode的形式来保存数据,强制类型转换只会返回第一个字符。

 

 


原创粉丝点击