C++: std::string 与 Unicode 如何结合?

关键字:std::string Unicode

转自:http://www.vckbase.com/document/viewdoc/?id=1293

 

一旦知道 TCHAR 和_T 是如何工作的,那么这个问题很简单。基本思想是 TCHAR 要么是char,要么是 wchar_t,这取决于_UNICODE 的值:

 

 

   1: // abridged from tchar.h 
   2:  
   3: #ifdef _UNICODE
   4:  
   5:       typedef wchar_t TCHAR;
   6:  
   7:       #define __T(x) L ## x
   8:  
   9: #else
  10:  
  11:      typedef char TCHAR;
  12:  
  13:      #define __T(x) x
  14:  
  15: #endif

  当你在工程设置中选择 Unicode 字符集时,编译器会用 _UNICODE 定义进行编译。如果你选择MBCS(多字节字符集),则编译器将不会带 _UNICODE 定义 。一切取决于_UNICODE 的值。同样,每一个使用字符指针的 Windows API 函数会有一个 A(ASCII) 和一个 (Wide/Unicode) 版本,这些版本的 实际定义也是根据 _UNICODE 的值来决定:

 

   1:  
   2:  #ifdef UNICODE
   3:     #define CreateFile CreateFileW
   4:  #else
   5:    #define CreateFile CreateFileA
   6:  #endif

 

  同样,_tprintf 和 _tscanf 对应于 printf 和 scanf。所有带"t"的版本使用 TCHARs 取代了chars。那么怎样把以上的这些应用到 std::string 上呢?很简单。STL已经有一个使用宽字符定义的wstring类 (在 xstring 头文件中定义)。string 和 wstring 均是使用 typedef 定义的模板类,基于 basic_string, 用它可以创建任何字符类型的字符串类。以下就是 STL 定义的 string 和 wstring:

   1:  
   2:   //(frominclude/xstring)
   3:   typedef basic_string< char, char_traits< char >, allocator< char > > string;
   4:   typedef basic_string< wchar_t, char_traits< wchar_t >, allocator< wchar_t > > wstring;

 

  模板被潜在的字符类型(char 或 wchar_t)参数化,因此,对于 TCHAR 版本,所要做的就是使用 TCHAR 来模仿定义:

   1: typedef basic_string< TCHAR, char_traits< TCHAR >, allocator< TCHAR > > tstring; 

  现在便有了一个 tstring,它基于 TCHAR——也就是说,它要么是 char,要么是 wchar_t,这取决于 _UNICODE 的值。 以上示范并指出了STL 是怎样使用 basic_string 来实现基于任何类型的字符串的。定义一个新的 typedef 并不是解决此问题最有效的方法。一个更好的方法是基于 string 和wstring 来简单 地定义 tstring,如下:

   1: #ifdef _UNICODE
   2:    #define tstring wstring
   3: #else
   4:    #define tstring string
   5: #endif

 

  这个方法之所以更好,是因为 STL 中已经定义了 string 和 wstring,那为什么还要使用模板来定义一个新的和其中之一一样的字符串类呢? 暂且叫它 tstring。可以用 #define 将 tstring 定义为 string 和 wstring,这样可以避免创建另外一个模板类( 虽然当今的编译器非常智能,如果它把该副本类丢弃,我一点也不奇怪)。[typedef 不创建新类,只是为某个类型引入限定范围的名称,typedef 决不会定义一个新的类型]。不管怎样,一旦定义了 tstring,便可以像下面这样编码:

   1: tstring s = _T("Hello, world");
   2: _tprintf(_T("s =%s\n"), s.c_str());

 

basic_string::c_str 方法返回一个指向潜在字符类型的常量指针;在这里,该字符类型要么是const char*,要么是const wchar_t*。

 

  顺便说一下,MFC 和 ATL 现在已经联姻,以便都使用相同的字符串实现。结合后的实现使用一个叫做 CStringT 的模板类,这在某种意义上 ,其机制类似 STL 的 basic_string,用它可以根据任何潜在的字符类型来创建 CString 类。在 MFC 包含文件afxstr.h中定义了三种字符 串类型,如下:

   1: typedef ATL::CStringT< wchar_t, StrTraitMFC< wchar_t > > CStringW;
   2: typedef ATL::CStringT< char, StrTraitMFC< char > > CStringA;
   3: typedef ATL::CStringT< TCHAR, StrTraitMFC< TCHAR > > CString;

 

CStringW,CStringA 和 CString 正是你所期望的:CString 的宽字符,ASCII 和 TCHAR 版本。

  那么,哪一个更好,STL 还是 CStirng?两者都很好,你可以选择你最喜欢的一个。但有一个问题要考虑到:就是你想要链接哪个库,以及你是否已经在使用 MFC/ATL。从编码 的角度来看,我更喜欢 CString 的两个特性:

  其一是无论使用宽字符还是char,都可以很方便地对 CString 进行初始化。

    CString s1 = "foo";

    CString s2 = _T("bar");

  这两个初始化都正常工作,因为 CString 自己进行了所有必要的转换。使用 STL 字符串,你必须使用_T()对tstring 进行初始化,因为你 无法通过一个char*初始化一个wstring,反之亦然。

  其二是 CString 对 LPCTSTR 的自动转换操作,你可以像下面这样编码:

    CString s;

    LPCTSTR lpsz = s;

 

  另一方面,使用 STL 必须显式调用 c_str 来完成这种转换。这确实有点挑剔,某些人会争辩说,这样能更好地了解何时进行转换。比如, 在C风格可变参数的函数中使用 CString 可能会有麻烦,像 printf:

    printf("s=%s\n", s); // 错误

    printf("s=%s\n", (LPCTSTR)s); // 必需的

  没有强制类型转换的话,得到的是一些垃圾结果,因为 printf 希望 s 是 char*。我敢肯定很多读者都犯过这种错误。防止这种灾祸是 STL 设计者不提供转换操作符的一个毋庸置疑的理由。而是坚持要你调用 c_str。一般来讲,喜欢使用 STL 家伙趋向于理论和学究气,而 Redmontonians(译者:指微软)的大佬们则更注重实用和散漫。嘿,不管怎样,std::string 和 CString 之间的实用差别是微不足道的。

时间: 2024-09-15 01:22:50

C++: std::string 与 Unicode 如何结合?的相关文章

关于std::string

主要注意的一个问题是:std::string 实际是类似一个 vector<char>的结构. 它里面是可以存放 ascii为0 的字符不算结尾 (否则 unicode方式的编码存放就有问题) 实际长度 用 length()获取 至于string赋值和构造有好几种方式,可以看文档. 举例说明:char c[10]="wer|\t";c[4] = 0;std::string s =c;由于c是char* 长度只能用strlen获取, strlen遇到0 就结束了,所以就丢失数

C2440: “delete”: 无法从“std::string”转换为“void*”

问题描述 C2440: "delete": 无法从"std::string"转换为"void*" #include ""stdafx.h""#include #include using namespace std;class A{public: virtual ~A() { cout << ""call A::~A()"" << endl;

std::string的Copy-on-Write:不如想象中美好

Copy-on-write(以下简称COW)是一种很重要的优化手段.它的核心思想是懒惰处理多个实体的资源请求,在多个实体之间共享某些资源,直到有实体需要对资源进行修改时,才真正为该实体分配私有的资源. COW技术的一个经典应用在于Linux内核在进程fork时对进程地址空间的处理.由于fork产生的子进程需要一份和父进程内容相同但完全独立的地址空间,一种做法是将父进程的地址空间完全复制一份,另一种做法是将父进程地址空间中的页面标记为"共享的"(引用计数+1),使子进程与父进程共享地址空

unsigned char [] 与 std::string 相互转换问题!C++

问题描述 unsigned char [] 与 std::string 相互转换问题!C++ 求这两个类型的相互转换的代码,同时还想问下怎样将大文件转换为 unsigned char [] 类型.(验证文件时过大读不进内存) 解决方案 http://zhidao.baidu.com/link?url=qx3_qtTjI-XcmUo_kyCRI3HhUmD0OZFg0DuGzMuUV57H3P8YRDder_KdQ43GOZ6V9knWDDWpFsWWrS67eGg0cbK83FvszP5JEpP

c++的问题- error C2440: “默认参数”: 无法从“const char [7]”转换为“std::string &amp;amp;amp;”

问题描述 error C2440: "默认参数": 无法从"const char [7]"转换为"std::string &" 代码如下: 1 #include 2 using namespace std; 3 class Student{ 4 string name; 5 public: 6 Student(string& n ="noName") :name(n){} 7 }; 8 class Teache

c++-boost::thread_specific_ptr&amp;amp;lt;std::string&amp;amp;gt; m_name 编译时无法解析的外部符号

问题描述 boost::thread_specific_ptr<std::string> m_name 编译时无法解析的外部符号 最近项目上需要做软件日志输出,头文件中声明了 class Logger { private: Logger(); ~Logger(); private: boost::thread_specific_ptr std::string m_name: boost::thread_specific_ptr m_logger: } 但是在编译时报错,无法解析的外部符号. 为

c++-哪位大神知道这个接口有什么不好吗? bool IsXP(std::string a);

问题描述 哪位大神知道这个接口有什么不好吗? bool IsXP(std::string a); 面试中遇到的问题,面试官也没给解答.求大神知道,这个接口有什么不好: bool IsXP(std::string a); 我觉得是这样: bool IsXP(const std::string &a); 解决方案 对,字符要引用,而且一般还要加const增强健壮性 解决方案二: 你的解答可以啊.引用,常量参数都是更好的方式

利用C++实现从std::string类型到bool型的转换_C 语言

利用输入字符串流:std::istringstream 复制代码 代码如下: bool b;std::string s = "true";std::istringstream(s) >> std::boolalpha >> b; 但当字符串s为"1"时,上面的代码无法正确转换,此时应该用: 复制代码 代码如下: bool b;std::string s = "1";istringstream(s) >> b;

c#调用dll,c++的std::string参数怎么处理,谢谢

问题描述 //c++中的dll函数,参数为std::string,函数的目的是将值赋给nameextern"C"_declspec(dllexport)voidGetInfo(std::string&strName,std::stringstrDevice);那么c#调用它,参数怎么写呢,谢谢,std::string在c#中没有对应的类型,如果用System.String程序会崩溃 解决方案 解决方案二:原来想这种传出的,要用stringBuilder,用string不行,如果