字符串表示与转换

    windows 编程中,存在几种字符串表示方式,包括:

    1)C-Style 字符串 char* / wchar_t*;

    2)C++ STL 字符串 std::string / std::wstring;

    3)  ATL/MFC 字符串 CStringA / CStringW;

    以上每个版本都有对应的多字节(MBCS)与Unicode(DBCS)表示,其中多字节存在不同编码方案,使用代码页区分。在 windows 系统中,常见代码页有:

    1)MS-DOS Latin US, code page 437,使用一个八位字节表示拉丁字符;

    2)windows code page 1251 for Cyrillic, 使用一个八位字节表示斯拉夫字符;

    3)code page 936/950/932/949 for ideographic,分别表示 简体中文/繁体中文/日语/韩语,使用一个八位字符表示拉丁字符,使用两个八位字符表示象形文字;

    针对象形文字,使用 strlen 函数求字符串长度是没有意义的,strlen 函数简单返回字符串中以 '\0' 结尾前字符个数。

    Unicode 使用两个字节表示一个字符,前128位与 ASCII(American Standard Code for Information Interchange) 保持一致。在使用非象形文字时语言时,有一半空间被浪费,故基于 Unicode 字符进行在编码,形成 utf8。这样,针对拉丁语系,斯拉夫语系等仅需要一个字符表示 Unicode 编码,而象形文字使用2,3,4个字节编码,具体见博客  ”字符集及编码“。在 visual c++开发中,utf8 编码可看作一种特殊代码页,使用函数 WideCharToMultiByte(CP_UTF8,...) 可以得到。

    

    如何维护在一个源文件中维护两种编码方案(MBCS & UNICODE)?

    winows 系统如下定义:

 

 1 typedef wchar_t WCHAR;    // wc,   16-bit UNICODE character
 2 
 3 #ifdef  UNICODE   
 4 // PTCHAR is a pointer to WCHAR 
 5 typedef WCHAR TCHAR, *PTCHAR;
 6 #else
 7 // PTCHAR is a pointer to char
 8 typedef char TCHAR, *PTCHAR;
 9 #endif 
10 
11 #ifdef  _UNICODE
12 #define _tcscpy        wcscpy
13 #define _tcslen         wcslen
14 ...
15 #else
16 #define _tcscpy     strcpy
17 #define _tcslen     strlen
18 ...
19 #endif
20 
21 #ifdef  _UNICODE
22 #define __T(x)      L ## x
23 #define __TEXT(quote) L##quote 
24 #else
25 #define __T(x)      x
26 #define __TEXT(quote) quote
27 #endif
28 
29 // _T(x) __T(x) TEXT(x) _TEXT(x) __TEXT(x) same meaning
30 #define _T(x)       __T(x)
31 #define _TEXT(x)    __T(x)
32 #define TEXT(quote) __TEXT(quote)

    根据以上定义,可以在使用一个源文件维护 C-Style 字符串,具体如下:

1 TCHAR *sz = _T("ch中国");
2 int iLen = _tcslen(sz);
3 TCHAR *sz2 = new TCHAR[iLen + 1];
4 _tcscpy(sz2, sz);
5 delete []sz2;

 

    在项目 Properties->Configuration Prooperties->General 下选择 Use Multi-Byte Character Set(or Not Set ),iLen 值为 6,其中每个汉字使用两个字节;当选择 Use Unicode Character Set 时,iLen 值为 4, 表示 sz 有 4 个字符。

    C++ STL 字符串 与 ATL/MFC 字符串是对 TCHAR 字符数据进行封装,表示如下:

 

 1 // c++ string
 2 typedef basic_string<char, char_traits<char>, allocator<char> >
 3     string;
 4 typedef basic_string<wchar_t, char_traits<wchar_t>,
 5     allocator<wchar_t> > wstring;
 6 
 7 // atl/mfc string
 8 typedef ATL::CStringT< wchar_t, StrTraitMFC_DLL< wchar_t > > CStringW;
 9 typedef ATL::CStringT< char, StrTraitMFC_DLL< char > > CStringA;
10 typedef ATL::CStringT< TCHAR, StrTraitMFC_DLL< TCHAR > > CString;
11 
12 // 由于c++ string 没有提供一个 TCHAR 版本,通过增加如下定义,
13 // 实现多字节与Unicode自动转换
14 #ifdef _UNICODE
15 #define tstring std::wstring
16 #else
17 #define tstring std::string
18 #endif

 

    通过以上定义,使用 tstring(自定义),CString 可以在一个源文件中维护两种类型字符串。windows 也允许使用特定字符集字符串,提供了 MBCS/Unicode 之间转换函数,具体如下:

 

 1 // char* -> wchar_t*
 2 //char *sz1 = "ch中国";
 3 // 获取 sz1 字符串转换为 Unicode 长度
 4 int iLen = MultiByteToWideChar(CP_ACP, 0, sz1, strlen(sz1), NULL, 0);
 5 wchar_t* sz2 = new wchar_t[iLen + 1];
 6 MultiByteToWideChar(CP_ACP, 0, sz1, strlen(sz1), sz2, iLen);
 7 sz2[iLen] = '\0';  // 以 '\0' 结尾字符串
 8 
 9 // wchar_t* -> char*
10 wchar_t* sz3 = L"ch中国";
11 // 获取 sz3 字符串转换为 多字节 长度
12 int iLen2 = WideCharToMultiByte(CP_ACP, 0, sz3, wcslen(sz3), NULL, 0, NULL, NULL);
13 char *sz4 = new char[iLen2 + 1];
14 WideCharToMultiByte(CP_ACP, 0, sz3, wcslen(sz3), sz4, iLen2, NULL, NULL);
15 sz4[iLen2] = '\0'; // 可不使用 L 标志,因为单个字符系统可以零补齐
16 
17 // CStringA -> CStringW
18 CStringA szA("ch中国");
19 CStringW szW(szA);
20 
21 // CStringW -> CStringA
22 CStringW szW2(L"ch中国");
23 CStringA szA2(szW2);
24 
25 
26 // unicode -> utf8 -> Unicode
27 // vs 默认使用 CP_ACP 翻译多字节,当需要查看 utf8 编码字符串时,可在 watch 窗口添加 ,s8 查看
28 wchar_t *szUtf16 =  L"ch中国";
29 int len = WideCharToMultiByte(CP_UTF8, 0, szUtf16, wcslen(szUtf16), NULL, 0, NULL, NULL);
30 char *szUtf8 = new char[len + 1];
31 WideCharToMultiByte(CP_UTF8, 0, szUtf16, wcslen(szUtf16), szUtf8, len, NULL, NULL);
32 szUtf8[len] = '\0';
33 int len2 = MultiByteToWideChar(CP_UTF8, 0, szUtf8, strlen(szUtf8), NULL, 0);
34 wchar_t *szUtf16_2 = new wchar_t[len2 + 1];
35 MultiByteToWideChar(CP_UTF8, 0, szUtf8, strlen(szUtf8), szUtf16_2, len2);
36 szUtf16_2[len2] = '\0';

    编程过程中经常使用不同类型字符串,如何在不同类型字符串见转换呢?代码如下:

 

 1 // TCHAR* <-> CString
 2 TCHAR *sz = _T("ch中国");
 3 CString cstr(sz);
 4 TCHAR* sz2 = cstr.GetBuffer();
 5 
 6 // TCHAR* <-> tsring
 7 tstring tstr(sz);
 8 const TCHAR* sz3 = tstr.c_str();  // tstr.data() is also ok
 9 
10 // CString <-> tstring
11 CString cstr2;
12 tstring tstr2;
13 tstr2 = cstr.GetBuffer();
14 cstr2 = tstr.c_str();

 

posted @ 2020-03-16 11:46  罗飞居  阅读(482)  评论(0编辑  收藏  举报