关于ASCII ,DBCS,UNICODE编码及字符串类型总结

来源:互联网 发布:vim python ide 编辑:程序博客网 时间:2024/06/16 11:45

最近因为项目需求,在windows平台下总是碰到一些关于字符串类型的变换,吃了不少苦头,索性花了这个晚上来整理下有关字节的知识,碰到的困难以及自己的一些解决方案。

一,字符的基础  ASCII DBCS( MBCS ) UNICODE

1.1ASCII( SBCS )

 ASCII 码使用指定的位或二进制数组合来表示128 256 种可能的字符。标准ASCII 码也叫基础ASCII码,使用二进制数来表示所有的大写和小写字母,数字9、标点符号, 以及在美式英语中使用的特殊控制字符。其中:

031127(33)控制字符或通信专用字符(其余为可显示字符),如控制符:LF(换行)、CR回车)、FF(换页)、DEL(删除)、BS(退格)BEL(响铃)等;通信专用字符:SOH(文头)、EOT(文尾)、ACK(确认)等;ASCII值为8910 13 分别转换为退格、制表、换行和回车字符。它们并没有特定的图形显示,但会依不同的应用程序,而对文本显示有不同的影响。

32126(95)字符(32sp是空格),其中485709十个阿拉伯数字

659026个大写英文字母( A-Z ),97122号为26个小写英文字母( a-z )

单字节字符集(single-byte character set or SBCS)。在这种编码模式下,所有的字符都只用一个字节表示。ASCIISBCS。一个字节表示的0用来标志SBCS字符串的结束。

1.2DBCS( MBCS )

英语用ascii编码就够了,但是我们知道,世界上很多国家都有自己的文字,ascii肯定是不能满足,在这里我们就讨论下中文字符,对于中文而言,则必须使用两个字节(byte)来代表一个字符,具第一个字节必须大于127(所以我们有许程序判断中文都是以ascii码大于127作为条件)以上用两个字节来表示一个中文的方式,在习惯上称为双字节(DBCS: Double-Byte Character Set),由于Windows里使用的多字节字符绝大部分是两个字节长,所以MBCS常被用DBCS代替。

我们运行下面这段代码:

#include <stdio.h>#include <string.h>int main(){char *str1="hello world!";char *str2="世界,你好!";char *str3="我aA你";printf("the length of str1=%d\n",strlen(str1));printf("the length of str2=%d\n",strlen(str2));printf("the length of str3=%d\n",strlen(str3));return 0;}

    我们可以看出中文字符占两个字节,英文字符占一个字节。

1.3UNICODE

虽然双字节(DBCS)足以解决中英文字符混合使用情况,但对于不同字符系统而言,必须经过字符码转换,非常麻烦。例如:中英文混合情况,日文,韩文等等。 为解决这个问题,Apple,Xerox,Microsoft,IBM,Novell,Borland...很多公司联合起来制订了一套可以适用于全世界所有国家的字符码,就称为Unicode ,java的内核就是16位双字节编码Unicode为基准

char类型表示Unicode编码方案中的字符。Unicode可同时包含65536个字符,ASCII/ANSI只包含255个字符,实际上是Unicode的一个子集。Unicode字符通常用十六进制编码方案表示,范围在'\u0000''\uFFFF'之间。\u0000\u00FF表示ASCII/ANSI字符。\u表示这是一个Unicode值。

二,windows平台下各种字符串定义

    VC6.0默认的是DBCS字符集,VS默认的是UNICODE字符集。

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个字节,故上述数组asizeof(a) = 14

TCHAR / _T( ) :

    如果在程序中既包括ANSI又包括Unicode编码,需要包括头文件tchar.hTCHAR是定义在该头文件中的宏,它视你是否定义了_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,那么就不应该使用ANSIstrXXX函数或者UnicodewcsXXX函数了,而必须使用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"));

    这样我们用TCHAR_tcscpy等就可以实现在UNICODE字符集和DBCS字符集兼容,明显地,这样同样的代码可以在VC6.0VS平台下运行。


2.1、在字符串前加一个L作用:

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

  strlen("asd")   =   3;  

  strlen(L"asd")   =   6;

2.2、_T宏可以把一个引号引起来的字符串,根据你的环境设置,使得编译器会根据编译目标环境选择合适的(Unicode还是ANSI)字符处理方式

   如果你定义了UNICODE,那么_T宏会把字符串前面加一个L。这时 _T("ABCD") 相当于 L"ABCD" ,这是宽字符串。

   如果没有定义,那么_T宏不会在字符串前面加那个L_T("ABCD") 就等价于 "ABCD"

2.3、TEXT,_TEXT _T 一样的

如下面三语句:  

  TCHAR   szStr1[]   =   TEXT("str1");  

  char   szStr2[]   =   "str2";  

  WCHAR   szStr3[]   =   L("str3");  

  那么第一句话在定义了UNICODE时会解释为第三句话,没有定义时就等于第二句话。  

  但二句话无论是否定义了UNICODE都是生成一个ANSI字符串,而第三句话总是生成UNICODE字符串。  

  为了程序的可移植性,建议都用第一种表示方法。  

  但在某些情况下,某个字符必须为ANSIUNICODE,那就用后两种方法。

 

2.4、_T()函数详解

_T("")是一个宏,他的作用是让你的程序支持Unicode编码

因为Windows使用两种字符集ANSIUNICODE

前者就是通常使用的单字节方式,

但这种方式处理象中文这样的双字节字符不方便,

容易出现半个汉字的情况。

而后者是双字节方式,方便处理双字节字符。

Windows NT的所有与字符有关的函数都提供两种方式的版本,而Windows 9x只支持ANSI方式。

如果你编译一个程序为ANSI方式,

_T实际不起任何作用。

而如果编译一个程序为UNICODE方式,则编译器会把"Hello"字符串以UNICODE方式保存。_T_L的区别在于,_L不管你是以什么方式编译,一律以UNICODE方式保存。

 

LPSTR32bit指针指向一个字符串,每个字符占1字节

LPCSTR:32-bit指针指向一个常字符串,每个字符占1字节

LPWSTR32bit指针指向一个字符串,每个字符占2字节

LPCWSTR:32-bit指针指向一个常字符串,每个字符占2字节

LPCTSTR:32-bit指针指向一个常字符串,每字符可能占1字节或2字节,取决于Unicode是否定义

LPTSTR:32-bit指针每字符可能占1字节或2字节,取决于Unicode是否定义

 

L是表示字符串资源为Unicode的。

比如

wchar_t Str[] = L"Hello World!";

这个就是双子节存储字符了。

_T是一个适配的宏~

#ifdef _UNICODE的时候

_T就是L

没有#ifdef _UNICODE的时候

_T就是ANSI的。

比如

LPTSTR lpStr = new TCHAR[32];

TCHAR* szBuf = _T("Hello");

以上两句使得无论是在UNICODE编译条件下都是正确编译的。

而且MS推荐你使用相匹配的字符串函数。

比如处理LPTSTR或者LPCTSTR 的时候,不要用strlen ,而是要用_tcslen

否则在UNICODE的编译条件下,strlen不能处理 wchar_t*的字符串。

T是非常有意思的一个符号(TCHARLPCTSTRLPTSTR_T()_TEXT()...),它表示使用一种中间类型,既不明确表示使用 MBCS,也不明确表示使用 UNICODE。那到底使用哪种字符集?编译的时候才决定

参考:http://www.cnblogs.com/wanghao111/archive/2009/05/25/1488816.html