在VS2010下使用 UNICODE 和 ANSI 的混合编程

时间:2021-08-03 19:57:18

1,在VS2010 编译器的菜单上 “项目----属性---左侧的配置属性----常规---右侧的 字符集 ”可以对项目所要使用的字符集进行定义,可以选择”使用Unicode字符集“、“使用多字节字符集”等等。

2,MessageBox 有三个版本:MessageBoxA, MessageBoxW, MessageBox;

****************************************

WINUSERAPI

int

WINAPI

MessageBoxA(

    __in_optHWND hWnd,

    __in_optLPCSTR lpText,

    __in_optLPCSTR lpCaption,

    __in UINTuType);

WINUSERAPI

int

WINAPI

MessageBoxW(

    __in_optHWND hWnd,

    __in_optLPCWSTR lpText,

    __in_optLPCWSTR lpCaption,

    __in UINTuType);

#ifdef UNICODE

#define MessageBox  MessageBoxW

#else

#define MessageBox  MessageBoxA

#endif // !UNICODE

**********************************************

即:如果项目设置使用UNICODE字符集, MessageBox 就是 MessageBoxW, 否则 MessageBox就是 MessageBoxA;

在MessageBoxA函数的第二和第三个参数的类型都是LPCSTR ,它是什么呢?

typedef __nullterminated CONST CHAR *LPCSTR, *PCSTR;

它是 CONST CHAR, CONST CHAR 是什么?

#ifndef CONST

#defineCONST              const

#endif

typedef char CHAR;

所以 CONST CHAR 就是 const char; 所以MessageBoxA中的第二和第三个参数要是多字节(ANSI)类型常量的。

在MessageBoxW函数的第二和第三个参数的类型都是LPCWSTR ,它是什么呢?

typedef __nullterminated CONST WCHAR *LPCWSTR, *PCWSTR;

它是 CONST WCHAR; CONST WCHAR又是什么?

#ifndef CONST

#defineCONST              const

#endif

#ifndef _MAC

typedef wchar_tWCHAR;    //wc,   16-bit UNICODEcharacter

#else

// some Macintosh compilers don't define wchar_t in a convenientlocation, or define it as a char

typedef unsigned shortWCHAR;    //wc,   16-bit UNICODEcharacter

#endif

所以CONST WCHAR 就是 const wchar_t ,所以MessageBoxW中的第二和第三个参数要是16位的UNICODE 常量。

3,CString 也有三个版本,CStringA, CStringW, CString;

**************************************************

typedef ATL::CStringT< wchar_t,StrTraitMFC_DLL< wchar_t >> CStringW;

typedef ATL::CStringT< char,StrTraitMFC_DLL< char >> CStringA;

typedef ATL::CStringT< TCHAR,StrTraitMFC_DLL< TCHAR >> CString;

******************************************************************

4,上面CString 模板中的 TCHAR 是什么?

*****************************************************************

//

// Neutral ANSI/UNICODE types and macros

//

#ifdef UNICODE                    // r_winnt

#ifndef _TCHAR_DEFINED

typedef WCHAR TCHAR, *PTCHAR;

typedef WCHAR TBYTE , *PTBYTE ;

#define _TCHAR_DEFINED

#endif

#else                // r_winnt

#ifndef _TCHAR_DEFINED

typedef char TCHAR, *PTCHAR;

typedef unsigned char TBYTE , *PTBYTE ;

#define _TCHAR_DEFINED

#endif

即:如果项目设置使用UNICODE字符集 ,TCHAR 就是 WCHAR,也就是wchar_t;否则 TCHAR 就是char;所以项目设置使用UNICODE字符集, CString就是CStringW, 否则CString 就是CStringA.

5 在给宽字节变量赋值时,可以在值前加“L”,也可以加“_T”,比如:

   wstring x(L"你好");

   CStringW y(L"再见");

   wstring x(_T("你好") );

   CStringW y(_T("再见") );

  在值前加“L”是常见用法,那么“_T”表示什么呢?

#define_T(x)      __T(x)

#define_TEXT(x)   __T(x)

那么 __T(x) 是什么?

#ifdef UNICODE                    // r_winnt

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

#else                // r_winnt

#define __TEXT(quote)quote        // r_winnt

#endif               // r_winnt

即:如果项目设置使用UNICODE字符集, “_T” 就相当于“L”,否则加“_T”就如同没加。


ANSI 与 UNICODE的混合编程。编程时,使用ANSI节省存储空间,但遇到处理中文时很不方便。如何使所编写的一个程序在处理英文时,使用ANSI字符集,在处理中文时,使用UNICODE字符集,并且不需要修改大量代码。

 a, 使用CString 类型的字符串变量;

 b, 使用MessageBox 来弹出消息;

 c, 使用TCHAR类型的字符变量;

 d, 使用_T来表示宽字节字符。

   在项目设置使用UNICODE字符集时,CString 就相当于CStringW,MessageBox就相当于MessageBoxW,TCHAR 就相当于wchar_t, _T就相当于L;

   在项目设置使用多字节字符集时,CString就相当于CStringA, MessageBox就相当于MessageBoxA,TCHAR就相当于char,_T就相当于不存在。

比如一条语句:

CString  x( _T("大家好") );

在项目设置使用UNICODE字符集时,CString 就相当于 CStringW, x中存储的字符长度为3,_T就相当于L;在项目设置使用多字节字符集时,CString 就相当于CStringA, x中存储的字符长度为6。

而string 和 wstring 却没有类似的转化功能。

typedef basic_string<char,char_traits<char>,allocator<char> >string;

typedef basic_string<wchar_t,char_traits<wchar_t>,allocator<wchar_t> >wstring

当然如果处于某种考虑,某个变量就要存储 宽字节字符,而不是存储ANSI字符,就可以显式的使用CStringW类型,而不是使用CString。


补充说明:编译错误。
_T只能把字符串文字量(也就是双引号括起来的字符串)或者字符文字量(也就是单引号括起来的字符)转化为所需的样子。它无法把一个CHAR转化为一个TCHAR,也无法把一个LPSTR转化为一个LPTSTR。

为什么会这样呢?答案是:因为C++语法。
目前的C++语法,支持两种字符串。一种是直接用引号括起的,比如"Hello, World.",另一种是用引号括起,前面再加一个字母L的,比如L"Hello, World."。前一种字符串的类型是char*,或者说是const char*,后一种字符串的类型是wchar_t*,或者说是const wchar_t*。
在Visual Studio 2010中,_T是一个宏。它的作用是:如果当前的工程设置是Unicode,则在前面加一个L,否则就什么也不加。换句话说,如果工程设置为Unicode,_T("a")就相当于L"a",否则,_T("a")就相当于"a"。楼主写一个_T(text),如果工程设置为Unicode,就变成了Ltext,于是编译就出错了:没有Ltext这个变量。

如何解决?
方法1、如果是从Visual Studio 6.0升级过来的代码,因为它的工程默认设置不是Unicode的,而Visual Studio 2010的工程默认设置是Unicode的,造成问题。遇到这种情况,直接在Visual Studio 2010里面修改工程设置为不是Unicode即可。
方法2、对于那个函数而言,可以调用TextOut的非Unicode版本。
TextOut(xdc,x,y,_T(text),strlen(text));
修改为
TextOutA(xdc,x,y,text,strlen(text));
方法3、如果彻底一点,一定要用Unicode的话,微软提供了MultiByteToWideChar函数,可以用于转化,楼主可以查查这方面的资料。