windows字符类型

windows字符类型

所谓的短字符,就是用8bit来表示的字符,典型的应用是ASCII码.而宽字符,顾名思义,就是用16bit表示的字符,典型的有UNICODE.关于windows下的ASCII和UNICODE的更多信息,能够参考这两本经典著做:《windows 程序设计》,《windows 核心编程》.这两本书关于这两种字符都有比较详细的解说.

宽字符转换为多个短字符是一个难点,不过咱们只要掌握到其中的要领,即可如鱼得水.


char:
ANSI字符串,可用字符串处理函数strcat( ),strcpy( ), strlen( )等以str打头的函数。

wchar_t :
wchar_t是Unicode字符的数据类型,它的实际定义为:typedef unsigned short wchar_t;
wchar_t 可用字符串处理函数:wcscat(),wcscpy(),wcslen()等以wcs打头的函数。

WCHAR:
在头文件中有这样的定义:typedef wchar_t WCHAR; 因此WCHAR实际就是wchar_t。
在C语言里面提供了_UNICODE宏(有下划线),在Windows里面提供了UNICODE宏(无下划线),只要定了_UNICODE宏和UNICODE宏,系统就会自动切换到UNICODE版本,不然,系统按照ANSI的方式进行编译和运行。只定义了宏并不能实现自动的转换,他还须要一系列的字符定义支持。

TCHAR:
若是定义了UNICODE宏则TCHAR被定义为wchar_t。typedef wchar_t TCHAR; 不然TCHAR被定义为char typedef char TCHAR;

ACHAR:
此类型是AUTODESK公司在adachar.h 头文件中定义的。
当定义了AD_UNICODE(AUTODESK公司使用UNICODE宏)时为wchar_t。



::setlocale(LC_ALL, "chs");



MultiByteToWideChar和WideCharToMultiByte用法详解

这个是咱们须要转化的多字节字符串:
char sText[20] = {"多字节字符串!OK!"};

咱们须要知道转化后的宽字符须要多少个数组空间.虽然在这个里程里面,咱们能够直接定义一个20*2宽字符的数组,而且事实上将运行得很是轻松愉快.但假如多字节字符串更多,达到上千个乃至上万个,咱们将会发现其中浪费的内存将会愈来愈多.因此以多字节字符的个数的两倍做为宽字符数组下标的声明绝对不是一个好主意.
所幸,咱们可以确知所须要的数组空间.
咱们只须要将MultiByteToWideChar()的第四个形参设为-1,便可返回所需的短字符数组空间的个数:
DWORD dwNum = MultiByteToWideChar (CP_ACP, 0, sText, -1, NULL, 0);

接下来,咱们只须要分配响应的数组空间:
wchar_t *pwText;
pwText = new wchar_t[dwNum];
if(!pwText)
{
delete []pwText;
}

接着,咱们就能够着手进行转换了.在这里以转换成ASCII码作为例子:
MultiByteToWideChar (CP_ACP, 0, psText, -1, sText, dwSize);

最后,使用完毕固然要记得释放占用的内存:
delete []psText;


同理,宽字符转为多字节字符的代码以下:
wchar_t wText[20] = {L"宽字符转换实例!OK!"};
DWORD dwNum = WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,NULL,0,NULL,FALSE);
char *psText;
psText = new char[dwNum];
if(!psText)
{
delete []psText;
}
WideCharToMultiByte (CP_OEMCP,NULL,lpcwszStr,-1,psText,dwNum,NULL,FALSE);
delete []psText;

若是以前咱们已经分配好空间,而且因为字符串较短,能够不理会浪费的空间,仅仅只是想简单地将短字符和宽字符相互转换,那有没有什么简便的方法呢?

WIN32 API里没有符合这种要求的函数,但咱们能够本身进行封装:

//-------------------------------------------------------------------------------------
//Description:
// This function maps a character string to a wide-character (Unicode) string
//
//Parameters:
// lpcszStr: [in] Pointer to the character string to be converted
// lpwszStr: [out] Pointer to a buffer that receives the translated string.
// dwSize: [in] Size of the buffer
//
//Return Values:
// TRUE: Succeed
// FALSE: Failed
//
//Example:
// MByteToWChar(szA,szW,sizeof(szW)/sizeof(szW[0]));
//---------------------------------------------------------------------------------------
BOOL MByteToWChar(LPCSTR lpcszStr, LPWSTR lpwszStr, DWORD dwSize)
{
// Get the required size of the buffer that receives the Unicode
// string.
DWORD dwMinSize;
dwMinSize = MultiByteToWideChar (CP_ACP, 0, lpcszStr, -1, NULL, 0);

if(dwSize < dwMinSize)
{
return FALSE;
}


// Convert headers from ASCII to Unicode.
MultiByteToWideChar (CP_ACP, 0, lpcszStr, -1, lpwszStr, dwMinSize);
return TRUE;
}

//-------------------------------------------------------------------------------------
//Description:
// This function maps a wide-character string to a new character string
//
//Parameters:
// lpcwszStr: [in] Pointer to the character string to be converted
// lpszStr: [out] Pointer to a buffer that receives the translated string.
// dwSize: [in] Size of the buffer
//
//Return Values:
// TRUE: Succeed
// FALSE: Failed
//
//Example:
// MByteToWChar(szW,szA,sizeof(szA)/sizeof(szA[0]));
//---------------------------------------------------------------------------------------
BOOL WCharToMByte(LPCWSTR lpcwszStr, LPSTR lpszStr, DWORD dwSize)
{
DWORD dwMinSize;
dwMinSize = WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,NULL,0,NULL,FALSE);
if(dwSize < dwMinSize)
{
return FALSE;
}
WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,lpszStr,dwSize,NULL,FALSE);
return TRUE;
}


使用方法也很简单,示例以下:
wchar_t wText[10] = {L"函数示例"};
char sText[20]= {0};
WCharToMByte(wText,sText,sizeof(sText)/sizeof(sText[0]));
MByteToWChar(sText,wText,sizeof(wText)/sizeof(wText[0]));

这两个函数的缺点在于没法动态分配内存,在转换很长的字符串时可能会浪费较多内存空间;优势是,在不考虑浪费空间的状况下转换较短字符串很是方便.

2.MultiByteToWideChar()函数乱码的问题

有的朋友可能已经发现,在标准的WinCE4.2或WinCE5.0 SDK模拟器下,这个函数都没法正常工做,其转换以后的字符全是乱码.及时更改MultiByteToWideChar()参数也依然如此.
不过这个不是代码问题,其结症在于所定制的操做系统.若是咱们定制的操做系统默认语言不是中文,也会出现这种状况.因为标准的SDK默认语言为英文,因此确定会出现这个问题.而这个问题的解决,不能在简单地更改控制面板的"区域选项"的"默认语言",而是要在系统定制的时候,选择默认语言为"中文".
系统定制时选择默认语言的位置于:
Platform -> Setting... -> locale -> default language ,选择"中文",而后编译便可.

 >>>>>History of Character Sets (from Programming Windows)

  ●●The American Standard Code for Information Interchange (ASCII) had its origins in the late 1950s and was finalized in 1967.

  ●●The final code had 26 lowercase letters, 26 uppercase letters, 10 digits, 32 symbols, 33 control codes, and a space, for a total of 128 codes.

  ●●The basic problem we have here is that the world's written languages simply cannot be represented by 256 8-bit codes

  ●●Unicode is a uniform 16-bit system, thus allowing the representation of 65,536 characters. This is sufficient for all the characters and ideographs in all the written languages of the world, including a bunch of math, symbol, and dingbat collections.

  ●●ANSI C supports character sets that require more than one byte per character through a concept called "wide characters."

  ●●Wide characters aren't necessarily Unicode. Unicode is one possible wide-character encoding.

  ●●Wide characters in C are based on the wchar_t data type, which is defined in several header files, including WCHAR.H, like so:

  typedef unsigned short wchar_t ;

  To define a variable containing a single wide character, use the following statement:

  wchar_t c = `A' ;

  You can also define an initialized pointer to a wide-character string:

  wchar_t * p = L"Hello!" ;

  Similarly, you can define an array of wide characters this way:

  static wchar_t a[] = L"Hello!" ;

  The string again requires 14 bytes of storage, and sizeof (a) will return 14.

  ●●>>>>>>>>>>win32

  TCHAR.H provides a set of alternative names for the normal run-time library functions requiring string parameters (for example, _tprintf and _tcslen). These are sometimes referred to as "generic"function names because they can refer to either the Unicode or non-Unicode versions of the functions.

  TCHAR.H also solves the problem of the two character data types with a new data type named TCHAR.

  If the _UNICODE identifier is defined, TCHAR is wchar_t:

  typedef wchar_t TCHAR ;

  Otherwise, TCHAR is simply a char:

  typedef char TCHAR ;

  If the _UNICODE identifier is defined, a macro called __T is defined like this:

  #define __T(x) L##x

  If the _UNICODE identifier is not defined, the __T macro is simply defined in the following way:

  #define __T(x) x

  ●●>>>>>>>---- arx2004

  在 adesk.h 中

  // Continued use of the type "char" is prohibited. Please

  // use only the abstract type "ACHAR" below, to contain

  // character information.

  typedef char ACHAR;

  ●●>>>>>>>------arx2007

  在 adesk.h 中,有变化

  #include "AdAChar.h" // ACHAR typedef

  而在adaAChar.h 中

  typedef wchar_t ACHAR;

  //-------------------------------------------



L与_T("")区别

VC++里面定义字符串的时候,用_T来保证兼容性。VC++支持ascii和unicode两种字符类型,用_T能够保证从ascii编码类型转换到unicode编码类型的时候,程序不须要修改。

若是未来你不打算升级到unicode,那么也不须要_T。

_t("hello world")
在ansi的环境下,它是ansi的,若是在unicode下,那么它将自动解释为双字节字符串,既unicode编码。
这样作的好处,不论是ansi环境,仍是unicode环境,都适用。

那么在VC++中,字符串_T("ABC")和一个普通的字符串"ABC"有什么区别呢?

_T("ABC")
若是定义了unicode,它将表示为L"ABC",每一个字符为16位,宽字符串。

若是没有定义unicode,它就是ascii的"ABC",每一个字符为8位。

至关于

#ifdef _UNICODE
#define _T("ABC") L"ABC"
#else
#define _T("ABC") "ABC"
#endif


_T("ABC")中的一个字符和汉字同样,占两个字节,而在"ABC"中,英文字符占一个字节,汉字占两个字节。



1、 在字符串前加一个L做用:
如 L"个人字符串" 表示将ANSI字符串转换成unicode的字符串,就是每一个字符占用两个字节。
strlen("asd") = 3;
strlen(L"asd") = 6;

2、 _T宏能够把一个引号引发来的字符串,根据你的环境设置,使得编译器会根据编译目标环境选择合适的(Unicode仍是ANSI)字符处理方式
若是你定义了UNICODE,那么_T宏会把字符串前面加一个L。这时 _T("ABCD") 至关于 L"ABCD" ,这是宽字符串。
若是没有定义,那么_T宏不会在字符串前面加那个L,_T("ABCD") 就等价于 "ABCD"

3、TEXT,_TEXT 和_T 同样的

以下面三语句:
TCHAR szStr1[] = TEXT("str1");
char szStr2[] = "str2";
WCHAR szStr3[] = L("str3");
那么第一句话在定义了UNICODE时会解释为第三句话,没有定义时就等于第二句话。
但二句话不管是否认义了UNICODE都是生成一个ANSI字符串,而第三句话老是生成UNICODE字符串。
为了程序的可移植性,建议都用第一种表示方法。
但在某些状况下,某个字符必须为ANSI或UNICODE,那就用后两种方法。



经常使用的unicode数据类型
在PPC开发中,使用的是unicode字符集,因此会常常用到一些数据类型,如下就是一些经常使用类型:
WCHAR :一个unicode字符。
LPWSTR:指向一个unicode字符的指针。
LPCWSTR:指向一个unicode字符串常量的指针。
TEXT("")和L""是windows.h中定义的宏,这两个在使用上常常是混用的,也没有什么区别,可是在使用时,最好仍是用TEXT("")而不是L""。由于,L""只能生成unicode字符串,而TEXT("")与目标环境相关,在winCE下生成unicode字符串,在win9X下则生成ANSI字符串,其经常使用简写为_T("")。


关于char, wchar_t, TCHAR, _T(),L,宏 _T、TEXT,_TEXT、L

char :单字节变量类型,最多表示256个字符,

wchar_t :宽字节变量类型,用于表示Unicode字符,

它实际定义在<string.h>里:typedef unsigned short wchar_t。

为了让编译器识别Unicode字符串,必须以在前面加一个“L”,定义宽字节类型方法以下:

wchar_t c = `A' ;
wchar_t * p = L"Hello!" ;
wchar_t a[] = L"Hello!" ;

其中,宽字节类型每一个变量占用2个字节,故上述数组a的sizeof(a) = 14

TCHAR / _T( ) :
若是在程序中既包括ANSI又包括Unicode编码,须要包括头文件tchar.h。TCHAR是定义在该头文件中的宏,它视你是否认义了_UNICODE宏而定义成:
定义了_UNICODE: typedef wchar_t TCHAR ;
没有定义_UNICODE: typedef char TCHAR ;

#ifdef UNICODE
typedef char TCHAR;
#else
typede wchar_t TCHAR;
#endif
_T( )也是定义在该头文件中的宏,视是否认义了_UNICODE宏而定义成:
定义了_UNICODE: #define _T(x) L##x
没有定义_UNICODE: #define _T(x) x
注意:若是在程序中使用了TCHAR,那么就不该该使用ANSI的strXXX函数或者Unicode的wcsXXX函数了,而必须使用tchar.h中定义的_tcsXXX函数。

以strcpy函数为例子,总结一下:

Code
//若是你想使用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"));

CSDN:superarhow说: 不要再使用TCHAR和_T了!他分析了缘由后总结:如 果您正开始一个新的项目,请不管如何也要顶住压力,直接使用UNICODE编码!切记!您只须要对您的组员进行10分钟的培训,记住strcpy用 wcscpy,sprintf用swprintf代替,常数前加L,就能够了!它不会花您不少时间的,带给您的是稳定和安全!相信偶,没错的!!

1、 在字符串前加一个L做用:
如 L"个人字符串" 表示将ANSI字符串转换成unicode的字符串,就是每一个字符占用两个字节。
strlen("asd") = 3;
strlen(L"asd") = 6;
2、 _T宏能够把一个引号引发来的字符串,根据你的环境设置,使得编译器会根据编译目标环境选择合适的(Unicode仍是ANSI)字符处理方式
若是你定义了UNICODE,那么_T宏会把字符串前面加一个L。这时 _T("ABCD") 至关于 L"ABCD" ,这是宽字符串。
若是没有定义,那么_T宏不会在字符串前面加那个L,_T("ABCD") 就等价于 "ABCD"
3、TEXT,_TEXT 和_T 同样的
以下面三语句:
TCHAR szStr1[] = TEXT("str1");
char szStr2[] = "str2";
WCHAR szStr3[] = L("str3");
那么第一句话在定义了UNICODE时会解释为第三句话,没有定义时就等于第二句话。
但二句话不管是否认义了UNICODE都是生成一个ANSI字符串,而第三句话老是生成UNICODE字符串。
为了程序的可移植性,建议都用第一种表示方法。
但在某些状况下,某个字符必须为ANSI或UNICODE,那就用后两种方法。



4、修改字符串运算问题

 一些字符串操做函数须要获取字符串的字符数(sizeof(szBuffer)/sizeof(TCHAR)),而另外一些函数可能须要获取字符串的字节数sizeof(szBuffer)。您应该注意该问题并仔细分析字符串操做函数,以肯定可以获得正确的结果。
ANSI操做函数以str开头,如strcpy(),strcat(),strlen();
Unicode操做函数以wcs开头,如wcscpy,wcscpy(),wcslen();

MBCS 操做函数以_mbs开头 _mbscpy
ANSI/Unicode操做函数以_tcs开头 _tcscpy(C运行期库); TCHAR
ANSI/Unicode操做函数以lstr开头 lstrcpy(Windows函数);
考虑ANSI和Unicode的兼容,咱们须要使用以_tcs开头或lstr开头的通用字符串操做函数。

全部新的和未过期的函数在Windows2000中都同时拥有ANSI和Unicode两个版本。ANSI版本函数结尾以A表示;Unicode版本函数结尾以W表示。Windows会以下定义:
#ifdef UNICODE
#define CreateWindowEx CreateWindowExW
#else
#define CreateWindowEx CreateWindowExA
#endif // !UNICODE


字符集 实例
ANSI “string”
Unicode L“string”
ANSI/Unicode T(“string”)或_TEXT(“string”)if( szError[0] == _TEXT(‘J’) ){ }

5、printf和wprintf

printf("%s", "multibyte中文\n"); // ④
printf("%S", L"unicode中文\n"); // ⑤
wprintf(L"%S", "multibyte中文\n"); // ⑥
wprintf(L"%s", L"unicode中文\n"); // ⑦

  缺省状况下,⑤、⑦两条语句不能输出中文,这两条语句中字符串的形式是unicode形式的。若是在全部输出语句以前加上以下语句将C语言的全局locale设置为本地语言(C语言中只有全局locale)就能够正常输出了:

  setlocale(LC_CTYPE, ""); // ⑧

  但这会致使cout和wcout不能输出中文(汗,的确麻烦),将C语言的全局locale恢复后cout和wcout就正常了,以下所示:

  setlocale(LC_CTYPE, "C"); // ⑨

   但恢复后,printf和wprintf输出Unicode文本又不正常了(输出MultiByte文本老是正常的)。总不能每写一个 printf/wprintf就设置一次而后再恢复一次吧?因此,建议不要混用iostream和printf/wprintf,实在要混用,那就让 printf/wprintf只输出MultiByte字符串,这样不须要调用setlocale(),也就不会影响到cout和wcout。

若是要用wcout,须要在使用以前按语句①将其locale设置为本地语言;
若是要用ofstream或wofstream,要在打开文件以前按语句②将全局locale设为本地语言并保存初始的全局locale。而后在打开文件以后,按语句③将全局locale恢复为初始值;
不要混用iostream和printf/wprintf。若是要混用,只用printf/wprintf输出MultiByte字符串;
单独使用printf/wprintf时,若是要输出Unicode字符串,须要按语句⑧设置C语言的全局locale。若是只输出MultiByte字符串,则不需设置。
ios

相关文章
相关标签/搜索