网站留言板漏洞,php一台电脑做网站,视频网站内容规划,wordpress安装后转自#xff1a;http://blog.csdn.net/luoweifu/article/details/49382969 上一篇文章带你玩转Visual Studio——带你跳出坑爹的Runtime Library坑帮我们理解了Windows中的各种类型C/C运行时库及它的来龙去脉#xff0c;这是C开发中特别容易误入歧途的一个地方#xff0c;我…转自http://blog.csdn.net/luoweifu/article/details/49382969 上一篇文章带你玩转Visual Studio——带你跳出坑爹的Runtime Library坑帮我们理解了Windows中的各种类型C/C运行时库及它的来龙去脉这是C开发中特别容易误入歧途的一个地方我们对它进行了总结和归纳。本篇文章我们将继续讲解C开发中容易混淆的另一个概念——多字节字符集与Unicode字符集。 多字节字符与宽字节字符 char与wchar_t 我们知道C基本数据类型中表示字符的有两种char、wchar_t。 char叫多字节字符一个char占一个字节之所以叫多字节字符是因为它表示一个字时可能是一个字节也可能是多个字节。一个英文字符(如’s’)用一个char(一个字节)表示一个中文汉字(如’中’)用3个char(三个字节)表示看下面的例子。
void TestChar()
{char ch1 s; // 正确cout ch1: ch1 endl;char ch2 中; // 错误,一个char不能完整存放一个汉字信息cout ch2: ch2 endl;char str[4] 中; //前三个字节存放汉字中,最后一个字节存放字符串结束符\0cout str: str endl;//char str2[2] 国; // 错误str2 : array bounds overflow//cout str2 endl;
}123456789101112 结点如下 ch1:s ch2: str:中 wchar_t被称为宽字符一个wchar_t占2个字节。之所以叫宽字符是因为所有的字都要用两个字节(即一个wchar_t)来表示不管是英文还是中文。看下面的例子
void TestWchar_t()
{wcout.imbue(locale(chs)); // 将wcout的本地化语言设置为中文wchar_t wch1 Ls; // 正确wcout wch1: wch1 endl;wchar_t wch2 L中; // 正确,一个汉字用一个wchar_t表示wcout wch2: wch2 endl;wchar_t wstr[2] L中; // 前两个字节(前一个wchar_t)存放汉字中,最后两个字节(后一个wchar_t)存放字符串结束符\0wcout wstr: wstr endl;wchar_t wstr2[3] L中国;wcout wstr2: wstr2 endl;
}1234567891011121314 结果如下 ch1:s ch2:中 str:中 str2:中国 说明 1. 用常量字符给wchar_t变量赋值时前面要加L。如 wchar_t wch2 L’中’; 2. 用常量字符串给wchar_t数组赋值时,前面要加L。如 wchar_t wstr2[3] L”中国”; 3. 如果不加L对于英文可以正常但对于非英文(如中文)会出错。 string与wstring 字符数组可以表示一个字符串但它是一个定长的字符串我们在使用之前必须知道这个数组的长度。为方便字符串的操作STL为我们定义好了字符串的类string和wstring。大家对string肯定不陌生但wstring可能就用的少了。 string是普通的多字节版本是基于char的对char数组进行的一种封装。 wstring是Unicode版本是基于wchar_t的对wchar_t数组进行的一种封装。 string 与 wstring的相关转换 以下的两个方法是跨平台的可在Windows下使用也可在Linux下使用。
#include cstdlib
#include string.h
#include string// wstring string
std::string WString2String(const std::wstring ws)
{std::string strLocale setlocale(LC_ALL, );const wchar_t* wchSrc ws.c_str();size_t nDestSize wcstombs(NULL, wchSrc, 0) 1;char *chDest new char[nDestSize];memset(chDest,0,nDestSize);wcstombs(chDest,wchSrc,nDestSize);std::string strResult chDest;delete []chDest;setlocale(LC_ALL, strLocale.c_str());return strResult;
}// string wstring
std::wstring String2WString(const std::string s)
{std::string strLocale setlocale(LC_ALL, ); const char* chSrc s.c_str();size_t nDestSize mbstowcs(NULL, chSrc, 0) 1;wchar_t* wchDest new wchar_t[nDestSize];wmemset(wchDest, 0, nDestSize);mbstowcs(wchDest,chSrc,nDestSize);std::wstring wstrResult wchDest;delete []wchDest;setlocale(LC_ALL, strLocale.c_str());return wstrResult;
}123456789101112131415161718192021222324252627282930313233 字符集(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进行了扩展又有了EASCIIEASCII用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 各种类型的编译如果要更详细地了解字符集和字符编码请参考 字符集和字符编码Charset Encoding 工程里多字节与宽字符的配制 右键你的工程名-Properties设置如下 图 2 Character Set当设置为Use Unicode Character Set时会有预编译宏_UNICODE、UNICODE 图 3 Unicode 当设置为Use Multi-Byte Character Set时会有预编译宏_MBCS 图 4 Multi-Byte Unicode Character Set与Multi-Byte Character Set有什么区别呢 Unicode Character Set和Multi-Byte Character Set这两个设置有什么区别呢我们来看一个例子: 有一个程序需要用MessageBox弹出提示框
#include windows.hvoid TestMessageBox()
{::MessageBox(NULL, 这是一个测试程序!, Title, MB_OK);
}123456 上面这个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 // !UNICODE123456789101112131415161718192021 上面的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的功能是一样的是一个预定义的宏。
#define _T(x) __T(x)
#define _TEXT(x) __T(x)12 我们再看看__T(x)的定义发现它有两个
#ifdef _UNICODE
// ... 省略其它代码
#define __T(x) L ## x
// ... 省略其它代码
#else /* ndef _UNICODE */
// ... 省略其它代码
#define __T(x) x
// ... 省略其它代码
#endif /* _UNICODE */123456789 这下明白了吗当我们的工程的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* 相互转换方法 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程序进行字符串的处理和类型的转换。 关于CString更详细的用法请参考 CString与string、char*的区别和转换 CString的常见用法 参考文章 字符集和字符编码Charset Encoding 字符字节和编码 《windows核心编程系列》二谈谈ANSI和Unicode字符集 Dword、LPSTR、LPWSTR、LPCSTR、LPCWSTR、LPTSTR、LPCTSTR