发展历史【转】Visual Studio——多字节编码与Unicode码

 

多配节约字符与宽字节字符

1) char与wchar_t

俺们掌握C++基本数据列中意味着字符的发出少数栽:char、wchar_t。 
char叫多配节约字符,一个char占一个字节,之所以受多字节字符是因为她象征一个经常或者是一个字节也恐怕是多独字节。一个英文字符(如’s’)用一个char(一个字节)表示,一个华语汉字(如’中’)用3个char(三个字节)表示,看下的例子。

 1 void TestChar()
 2 {
 3     char ch1 = 's';             // 正确
 4     cout << "ch1:" << ch1 << endl;
 5     char ch2 = '中';             // 错误,一个char不能完整存放一个汉字信息
 6     cout << "ch2:" << ch2 << endl;
 7 
 8     char str[4] = "中";          //前三个字节存放汉字'中',最后一个字节存放字符串结束符\0
 9     cout << "str:" << str << endl;
10     //char str2[2] = "国";       // 错误:'str2' : array bounds overflow
11     //cout << str2 << endl;
12 }

结果如下:

ch1:s 
ch2: 
str:中

wchar_t被称为宽字符,一个wchar_t占2单字节。之所以让富字符是以兼具的许还使就此鲜个字节(即一个wchar_t)来表示,不管是英文还是中文。看下的事例:

 1 void TestWchar_t()
 2 {
 3     wcout.imbue(locale("chs"));     // 将wcout的本地化语言设置为中文
 4 
 5     wchar_t wch1 = L's';            // 正确
 6     wcout << "ch1:" << wch1 << endl;
 7     wchar_t wch2 = L'中';            // 正确,一个汉字用一个wchar_t表示
 8     wcout << "ch2:" << wch2 << endl;
 9 
10     wchar_t wstr[2] = L"中";         // 前两个字节(前一个wchar_t)存放汉字'中',最后两个字节(后一个wchar_t)存放字符串结束符\0
11     wcout << "str:" << wstr << endl;
12     wchar_t wstr2[3] = L"中国";
13     wcout << "str2:" << wstr2 << endl;
14 }

结果如下:

ch1:s 
ch2:中 
str:中 
str2:中国

说明: 
1.
为此时量字符给wchar_t变量赋值时,前面要加L。如: wchar_t wch2 =
L’中’; 
2.
因此时量字符串给wchar_t数组赋值时,前面要加L。如: wchar_t wstr2[3] =
L”中国”; 
3.
如无加L,对于英文可以健康,但对此非英文(如中文)会出错。

 

2)string与wstring

字符数组可以象征一个字符串,但她是一个定长的字符串,我们当使前要知道这数组的长度。为便宜字符串的操作,STL为我们定义好了字符串的类string和wstring。大家对string肯定不生疏,但wstring可能就就此底散失了。

string是寻常的多字节版本,是基于char的,对char数组进行的同种包装。

wstring是Unicode版本,是基于wchar_t的,对wchar_t数组进行的同样种植包装。

string与wstring的连锁转换

以下的个别单章程是跨越平台的,可当Windows下行使,也可在Linux下用。

 1 #include <cstdlib>
 2 #include <string.h>
 3 #include <string>
 4 
 5 // wstring => string
 6 std::string WString2String(const std::wstring& ws)
 7 {
 8     std::string strLocale = setlocale(LC_ALL, "");
 9     const wchar_t* wchSrc = ws.c_str();
10     size_t nDestSize = wcstombs(NULL, wchSrc, 0) + 1;
11     char *chDest = new char[nDestSize];
12     memset(chDest,0,nDestSize);
13     wcstombs(chDest,wchSrc,nDestSize);
14     std::string strResult = chDest;
15     delete []chDest;
16     setlocale(LC_ALL, strLocale.c_str());
17     return strResult;
18 }
19 
20 // string => wstring
21 std::wstring String2WString(const std::string& s)
22 {
23     std::string strLocale = setlocale(LC_ALL, ""); 
24     const char* chSrc = s.c_str();
25     size_t nDestSize = mbstowcs(NULL, chSrc, 0) + 1;
26     wchar_t* wchDest = new wchar_t[nDestSize];
27     wmemset(wchDest, 0, nDestSize);
28     mbstowcs(wchDest,chSrc,nDestSize);
29     std::wstring wstrResult = wchDest;
30     delete []wchDest;
31     setlocale(LC_ALL, strLocale.c_str());
32     return wstrResult;
33 }

 

字符集(Charcater Set)与字符编码(Encoding)

字符集(Charcater
Set或Charset):
大凡一个体系支持的保有抽象字符的集合,也即是一样多级字符的会师。字符是各种文字及标志的总称,包括各级邦文字、标点符号、图形符号、数字相当于。常见的字符集有:ASCII字符集、GB2312字符集(主要用来拍卖中文汉字)、GBK字符集(主要用以拍卖中文汉字)、Unicode字符集等。

字符编码(Character
Encoding):
凡一致模拟法则,使用该法则会对自然语言的字符的一个字符集(如字母表或音节表),与计算机能认识别的二进制数字进行交配。即她会当符号集合与数字系统间建立针对许提到,是信处理的同样起骨干技巧。通常人们之所以符号集合(一般情形下就算是仿)来抒发信息,而计算机的信息处理系统则是以二进制的数字来囤和处理信息的。字符编码就是拿记转换为电脑能识别的第二上前制编码。

一般一个字符集等同于一个编码方式,ANSI体系(ANSI是同样栽字符代码,为使计算机支持更多语言,通常采取
0x80~0xFF 范围的 2 独字节来代表 1 个字符)的字符集如ASCII、ISO
8859-1、GB2312、GBK等等都是这么。一般我们说一样种植编码还是针对性某同特定的字符集。 
一个字符集及呢得以有多种编码方式,例如UCS字符集(也是Unicode使用的字符集)上产生UTF-8、UTF-16、UTF-32等编码方式。

打计算机字符编码的上扬历史角度来拘禁,大概经历了三单等级: 
率先独号:ASCII字符集和ASCII编码。 
微机刚刚开仅支持英语(即拉丁字符),其它语言不克当电脑及囤积和出示。ASCII用一个字节(Byte)的7位(bit)表示一个字符,第一号置0。后来以表示再多的欧洲常常因此字符又针对ASCII进行了扩大,又生矣EASCII,EASCII用8员表示一个字符,使它们亦可多表示128单字符,支持了一部分西欧字符。

仲独号:ANSI编码(本地化) 
也而计算机支持再次多语言,通常采用
0x80~0xFF 范围的 2 单字节来代表 1 个字符。比如:汉字 ‘中’
在华语操作系统中,使用 [0xD6,0xD0] 这简单只字节存储。 
不等之国度与地方制定了不同之规范,由此有了
GB2312, BIG5, JIS 等分别的编码标准。这些使 2
独字节来表示一个字符的各种汉字延伸编码方式,称为 ANSI
编码。在简体中文系统下,ANSI 编码代表 GB2312
编码,在日文操作系统下,ANSI 编码代表 JIS 编码。 
不等 ANSI
编码之间互不兼容,当信息在列国中间交流时,无法以属于个别栽语言的契,存储在同一段
ANSI 编码的文本中。

其三单等级:UNICODE(国际化) 
为使国际中间信息交流更加惠及,国际集团制定了
UNICODE
字符集,为各种语言中之每一个字符设定了统一而唯一的数字编号,以满足超过语言、跨平台开展文本转换、处理的求。UNICODE
常见的来三种植编码方式:UTF-8(1单字节表示)、UTF-16((2只字节表示))、UTF-32(4独字节表示)。

咱得以据此一个树状图来代表出于ASCII发展而来之相继字符集及编码的道岔: 

发展历史 1

希冀1.各种类型的编译

倘若如再详细地问询字符集及字符编码请参见:

字符集及字符编码(Charset &
Encoding)

 

工里多字节约字符与宽字符的布置

右键你的工程名->Properties,设置如下: 

发展历史 2

图2.Character Set

 

1、当装为Use Unicode Character
Set时,会生出预编译宏:_UNICODE、UNICODE

发展历史 3

图3.Unicode

 

2、当装也Use Multi-Byte Character
Set时,会有预编译宏:_MBCS 

发展历史 4

图4.Multi-Byte

 

Unicode Character
Set与Multi-Byte Character Set有什么区别为?

Unicode Character Set和Multi-Byte
Character Set这半单装有啊区别吧?我们来拘禁一个例证: 
生一个程序要用MessageBox弹来提示框:

1 #include "windows.h"
2 
3 void TestMessageBox()
4 {
5     ::MessageBox(NULL, "这是一个测试程序!", "Title", MB_OK);
6 }

面这Demo非常简单不用多说了咔嚓!我们拿Character
Set设置也Multi-Byte Character
Set时,可以健康编译和运转。但当我们设置也Unicode Character
Set,则会发出以下编译错误:

error C2664: ‘MessageBoxW’ : cannot convert parameter 2 from ‘const char [18]’ to ‘LPCWSTR’

顿时是坐MessageBox有些许个版本,一个MessageBoxW针对Unicode版的,一个凡MessageBoxA针对Multi-Byte的,它们经不同宏进行分隔开,预设不同之宏会使用不同的版本。我们以了Use
Unicode Character
Set就预设了_UNICODE、UNICODE宏,所以编译时就是会见采取MessageBoxW,这时我们传入多字节常量字符串肯定会发题目,而相应传宽符的字符串,即将”Title”改为L”Title”就可以了,”这是一个测试程序!”也一样。

WINUSERAPI
int
WINAPI
MessageBoxA(
    __in_opt HWND hWnd,
    __in_opt LPCSTR lpText,
    __in_opt LPCSTR lpCaption,
    __in UINT uType);
WINUSERAPI
int
WINAPI
MessageBoxW(
    __in_opt HWND hWnd,
    __in_opt LPCWSTR lpText,
    __in_opt LPCWSTR lpCaption,
    __in UINT uType);
#ifdef UNICODE
#define MessageBox  MessageBoxW
#else
#define MessageBox  MessageBoxA
#endif // !UNICODE

上面的Multi-Byte Character
Set一般是凭借ANSI(多字节)字符集,关于ANSI请参考第二稍微节“字符集(Charcater
Set)与字符编码(Encoding)”。而Unicode Character
Set就是Unicode字符集,一般是乘UTF-16编码的Unicode。也就是说每个字符编码为寡单字节,两只字节可以表示65535只字符,65535独字符可以象征世界上绝大多数底语言。

诚如推荐使用Unicode的法子,因为它好适应各个国家语言,在展开软件国际时将会晤死便得。除非在针对存储要求老强的时刻,或使兼容C的代码时,我们才见面用多字节的计

 

理解_T()、_Text()宏及L” “

达同一不怎么节对MessageBox的调用中除去使用L”Title”外,还可行使_T(“Title”)和_TEXT(“Title”)。而且若晤面意识以MFC和Win32序中会再次多地行使_T和_TEXT,那_T、_TEXT和L之间有啊界别呢?

 通过第一聊节多字节约字符与宽字节字符我们了解表示多字节约字符(char)串常量时用一般的对仗挑起号括起来便可了,如”String
test”;而表示宽字节字符(wchar_t)串常量时要在引号前加L,如L”String
test”。

 

查tchar.h头文件之概念我们理解_T和_TEXT的意义是平的,是一个预定义的庞。

1 #define _T(x)       __T(x)
2 #define _TEXT(x)    __T(x)

我们重新看__T(x)底定义,发现她发星星点点只:

1 #ifdef  _UNICODE
2 // ... 省略其它代码
3 #define __T(x)      L ## x
4 // ... 省略其它代码
5 #else   /* ndef _UNICODE */
6 // ... 省略其它代码
7 #define __T(x)      x
8 // ... 省略其它代码
9 #endif  /* _UNICODE */

随即生知了吧?当我们的工的Character
Set设置也Use Unicode Character
Set时_T和_TEXT就见面在常量字符串前面加L,否则(即Use Multi-Byte Character
Set时)就见面因为相似的字符串处理。

 

Dword、LPSTR、LPWSTR、LPCSTR、LPCWSTR、LPTSTR、LPCTSTR

VC++中还有一部分常用的宏你也许会范糊涂,如Dword、LPSTR、LPWSTR、LPCSTR、LPCWSTR、LPTSTR、LPCTSTR。这里我们统一总结一下:

广大的宏:

类型 MBCS UNICODE
WCHAR wchar_t wchar_t
LPSTR char* char*
LPCSTR const char* const char*
LPWSTR wchar_t* wchar_t*
LPCWSTR const wchar_t* const wchar_t*
TCHAR char wchar_t
LPTSTR TCHAR*(或char*) TCHAR* (或wchar_t*)
LPCTSTR const TCHAR* const TCHAR*

P表示马上是一个指针。

T表示_T宏,这个宏用来代表您的字符是否利用UNICODE,
如果你的程序定义了UNICODE或者其它相关的巨,那么这字符或字符串将于看作UNICODE字符串,否则便是明媒正娶的ANSI字符串。

STR表示此变量是一个字符串。

C表示是一个常量,const。

LPTSTR:LPSTR、LPWSTR两者二挑同,取决于是否宏定义了UNICODE或ANSI

LPCTSTR: LPCSTR、LPCWSTR两者二增选同,取决于是否宏定义了UNICODE或ANSI

 1 #ifdef UNICODE
 2 
 3     typedef LPWSTR LPTSTR;
 4 
 5     typedef LPCWSTR LPCTSTR;
 6 
 7 #else
 8 
 9     typedef LPSTR LPTSTR;
10 
11     typedef LPCSTR LPCTSTR;
12 
13 #endif 

 

相互之间转换方法: 
LPWSTR->LPTSTR: W2T(); 
LPTSTR->LPWSTR: T2W(); 
LPCWSTR->LPCSTR: W2CT(); 
LPCSTR->LPCWSTR: T2CW();

ANSI->UNICODE: A2W(); 
UNICODE->ANSI: W2A();

 

字符串函数: 
还有局部字符串的操作函数,它们啊来同一
一针对承诺提到:

MBCS UNICODE
strlen(); wcslen();
strcpy(); wcscpy();
strcmp(); wcscmp();
strcat(); wcscat();
strchr(); wcschr();

透过这些函数和大的命名你也许就是发现了一些原理,一般含前缀w(或后缀W)的都是用来宽字符的,而不带来前缀w(或含有后缀A)的相似是用来多字节约字符的。

 

懂CString产生的因以及做事的机理

CString:动态的TCHAR数组,是针对TCHAR数组的等同种封闭。它是一个截然独立的类似,封装了“+”等操作符和字符串操作方法,换句话说即是CString是针对TCHAR操作的方的集。它的用意是利于WIN32序和MFC程序进行字符串的处理同类别的易。

 

转自《带您打转Visual
Studio——带你掌握多字节编码与Unicode码》

发表评论

电子邮件地址不会被公开。 必填项已用*标注