xml地图|网站地图|网站标签 [设为首页] [加入收藏]

您的位置:凤凰彩票app下载 > 戏剧 > CString-int-string-char-BSTR之间的转换

CString-int-string-char-BSTR之间的转换

发布时间:2019-11-14 21:50编辑:戏剧浏览(128)

    C++字符串完全指引之二 —— 字符串封装类

    一.CString, int, string, char*之间的转换

    原著:Michael Dunn

    string 转 CString

    作者:Chengjie Sun

    CString.Format("%s", string.c_str());
    char 转 CString
      CString.Format("%s", char*);
    char 转 string
      string s(char *);
    string 转 char *
      char *p = string.c_str();
    CString 转 string
      string s(CString.GetBuffer());

    原文出处:CodeProject:The Complete Guide to C++ Strings, Part II

    1.string -> CString
      CString. Format("%s", string.c_str());
      用c_str()确实比data()要好.
    2.char -> string
      string s(char *);
      你的只能初始化,在不是初始化的地方最好还是用assign().
    3.CString -> string
      string s(CString.GetBuffer());
      GetBuffer()后一定要ReleaseBuffer(),否则就没有释放缓冲区所占的空间.

    凤凰彩票官网app下载 1 引言

    《C++标准函数库》中:
    有三个函数可以将字符串的内容转换为字符数组和C—string
    1.data(),返回没有”“的字符串数组
    2.c_str(),返回有”“的字符串数组
    3.copy()

      因为C语言风格的字符串容易出错且不易管理,黑客们甚至利用可能存在的缓冲区溢出bug把C语言风格的字符串作为攻击目标,所以出现了很多字符串封装类。不幸的是,在某些场合下我们不知道该使用哪个字符串类,也不知道怎样把一个C风格的字符串转换成一个字符串封装类。
      这篇文章将介绍所有在Win32 API, MFC, STL, WTL 和 Visual C++ 运行库中出现的字符串类型。我将描述每一个类的用法,告诉大家怎样创建每一个类的对象以及怎样把一个类转换成其他类。受控字符串和Visual C++ 7中的类两部分是Nish完成的。
      为了更好的从这篇文章中受益,你必须要明白不同的字符类型和编码,这些内容我在第一部分中介绍过。

    CString 和 int互转
    将字符转换为整数,可以使用atoi、_atoi64或atol.

    Rule #1 of string classes
    

    将数字转换为CString变量,可以使用CString的Format函数。如

      使用cast来实现类型转换是不好的做法,除非有文档明确指出这种转换可以使用。
    促使我写这两篇文章的原因是字符串类型转换中经常遇到的一些问题。当我们使用cast把字符串从类型X转换到类型Z的时候,我们不知道为什么代码不能正常工作。各种各样的字符串类型,尤其是BSTR,几乎没有在任何一个地方的文档中被明确的指出可以用cast来实现类型转换。所以我想一些人可能会使用cast来实现类型转换并希望这种转换能够正常工作。
      除非源字符串是一个被明确指明支持转换操作符的字符串包装类,否则cast不对字符串做任何转换。对常量字符串使用cast不会起到任何作用,所以下面的代码:

    (1)CString s;
    int i = 64;
    s.Format("%d", i)

    void SomeFunc ( LPCWSTR widestr );
    main()
    {
      SomeFunc ( (LPCWSTR) "C:\foo.txt" );  // WRONG!
    }      
    

    Format函数的功能很强,值得你研究一下。

      肯定会失败。它可以被编译,因为cast操作会撤消编译器的类型检查。但是,编译可以通过并不能说明代码是正确的。
      在下面的例子中,我将会指明cast在什么时候使用是合法的。

    (2)void CStrDlg::OnButton1()
    {
    // TODO: Add your control notification handler code here
    CString ss="1212.12";
    int temp=atoi(ss);              //字符转换为整数
    CString aa;
    aa.Format("%d",temp);         //整数转换为字符
    AfxMessageBox("var is " + aa);
    }

    C-style strings and typedefs
    

    CString和char*互转

      正如我在第一部分中提到的,windows APIs 是用TCHARs来定义的,在编译时,它可以根据你是否定义_MBCS或者_UNICODE被编译成MBCS或者Unicode字符。你可以参看第一部分中对TCHAR的完整描述,这里为了方便,我列出了字符的typedefs

    (1)char * -> CString
    CString strtest;
    char * charpoint;
    charpoint="give string a value";
    strtest=charpoint;

    Type Meaning
    WCHAR Unicode character (wchar_t)
    TCHAR MBCS or Unicode character, depending on preprocessor settings
    LPSTR string of char (char*)
    LPCSTR constant string of char (const char*)
    LPWSTR string of WCHAR (WCHAR*)
    LPCWSTR constant string of WCHAR (const WCHAR*)
    LPTSTR string of TCHAR (TCHAR*)
    LPCTSTR constant string of TCHAR (const TCHAR*)

    (2)CString -> char *
    charpoint=strtest.GetBuffer(strtest.GetLength());
    标准C里没有string,char *==char []==string

      一个增加的字符类型是OLETYPE。它表示自动化接口(如word提供的可以使你操作文档的接口)中使用的字符类型。这种类型一般被定义成wchar_t,然而如果你定义了OLE2ANSI预处理标记,OLECHAR将会被定义成char类型。我知道现在已经没有理由定义OLE2ANSI(从MFC3以后,微软已经不使用它了),所以从现在起我将把OLECHAR当作Unicode字符。
    这里给出你将会看到的一些OLECHAR相关的typedefs:

    可以用CString.Format("%s",char *)这个方法来将char *转成CString。

    Type Meaning
    OLECHAR Unicode character (wchar_t)
    LPOLESTR string of OLECHAR (OLECHAR*)
    LPCOLESTR constant string of OLECHAR (const OLECHAR*)

    要把CString转成char *,用操作符(LPCSTR)CString就可以了。

      还有两个用于包围字符串和字符常量的宏定义,它们可以使同样的代码被用于MBCS和Unicode builds :

     

    Type Meaning
    _T(x) Prepends L to the literal in Unicode builds.
    OLESTR(x) Prepends L to the literal to make it an LPCOLESTR.

    CString-> char[100]
    char a[100];
    CString str("aaaaaa");
    strncpy(a,(LPCTSTR)str,sizeof(a));

      在文档或例程中,你还会看到好多_T的变体。有四个等价的宏定义,它们是TEXT, _TEXT, __TEXT和__T,它们都起同样的做用。

    CString类型的转换成int

    凤凰彩票官网app下载 2 COM 中的字符串 —— BSTR 和 VARIANT

    (1)CString类型的转换成int,可以使用atoi、_atoi64或atol。
    例:CString aaa = "16" ;
        int int_chage = atoi((lpcstr)aaa) ;

      很多自动化和COM接口使用BSTR来定义字符串。BSTRs中有几个"陷阱",所以这里我用单独的部分来说明它。
      BSTR 是 Pascal-style 字符串(字符串长度被明确指出)和C-style字符串(字符串的长度要通过寻找结束符来计算)的混合产物。一个BSTR是一个Unicode字符串,它的长度是预先考虑的,并且它还有一个0字符作为结束标记。下面是一个BSTR的示例:

    (2)将数字转换为CString变量,可以使用CString的Format函数。

     

    例:CString s;
    int i = 64;
    s.Format("%d", i)

    06 00 00 00 42 00 6F 00 62 00 00 00
    --length-- B o b EOS

    CString ss="1212.12";
    int temp=atoi(ss);
    CString aa;
    aa.Format("%d",temp);

      注意字符串的长度是如何被加到字符串数据中的。长度是DWORD类型的,保存了字符串中包含的字节数,但不包括结束标记。在这个例子中,"Bob"包含3个Unicode字符(不包括结束符),总共6个字节。字符串的长度被预先存储好,以便当一个BSTR在进程或者计算机之间被传递时,COM库知道多少数据需要传送。(另一方面,一个BSTR能够存储任意数据块,而不仅仅是字符,它还可以包含嵌入在数据中的0字符。然而,由于这篇文章的目的,我将不考虑那些情况)。
      在 C++ 中,一个 BSTR 实际上就是一个指向字符串中第一个字符的指针。它的定义如下:

    如果是使用char数组,也可以使用sprintf函数。

    BSTR bstr = NULL;
      bstr = SysAllocString ( L"Hi Bob!" ); 
      if ( NULL == bstr )
        // out of memory error 
      // Use bstr here...
     SysFreeString ( bstr );      
    

    数字->字符串除了用CString::Format,还有FormatV、sprintf和不需要借助于Afx的itoa

    自然的,各种各样的BSTR封装类为你实现内存管理。
      另外一个用在自动化接口中的变量类型是VARIANT。它被用来在无类型(typeless)语言,如Jscript和VBScript,来传递数据。一个VARIANT可能含有很多不同类型的数据,例如long和IDispatch*。当一个VARIANT包含一个字符串,字符串被存成一个BSTR。当我后面讲到VARIANT封装类时,我会对VARIANT多些介绍。

     

    凤凰彩票官网app下载 3 字符串封装类

    string->char*

      到目前为止,我已经介绍了各种各样的字符串。下面,我将说明封装类。对于每个封装类,我将展示怎样创建一个对象及怎样把它转换成一个C语言风格的字符串指针。C语言风格的字符串指针对于API的调用,或者创建一个不同的字符串类对象经常是必需的。我不会介绍字符串类提供的其他操作,比如排序和比较。
      重复一遍,除非你确切的明白结果代码将会做什么,否则不要盲目地使用cast来实现类型转换。

    string aa("aaa");

    凤凰彩票官网app下载 4 CRT提供的类

    char *c=aa.c_str();

    _bstr_t
      _bstr_t是一个对BSTR的完整封装类,实际上它隐藏了底层的BSTR。它提供各种构造函数和操作符来访问底层的C语言风格的字符串。然而,_bstr_t却没有访问BSTR本身的操作符,所以一个_bstr_t类型的字符串不能被作为输出参数传给一个COM方法。如果你需要一个BSTR*参数,使用ATL类CComBSTR是比较容易的方式。
      一个_bstr_t字符串能够传给一个接收参数类型为BSTR的函数,只是因为下列3个条件同时满足。首先,_bstr_t有一个向wchar_t*转换的转换函数;其次,对编译器而言,因为BSTR的定义,wchar_t*和BSTR有同样的含义;第三,_bstr_t内部含有的wchar_t*指向一片按BSTR的形式存储数据的内存。所以,即使没有文档说明,_bstr_t可以转换成BSTR,这种转换仍然可以正常进行。

     

    // Constructing
    _bstr_t bs1 = "char string";       // construct from a LPCSTR
    _bstr_t bs2 = L"wide char string"; // construct from a LPCWSTR
    _bstr_t bs3 = bs1;                 // copy from another _bstr_t
    _variant_t v = "Bob";
    _bstr_t bs4 = v;                   // construct from a _variant_t that has a string
    
    // Extracting data
    LPCSTR psz1 = bs1;              // automatically converts to MBCS string
    LPCSTR psz2 = (LPCSTR) bs1;     // cast OK, same as previous line
    LPCWSTR pwsz1 = bs1;            // returns the internal Unicode string
    LPCWSTR pwsz2 = (LPCWSTR) bs1;  // cast OK, same as previous line
    BSTR    bstr = bs1.copy();      // copies bs1, returns it as a BSTR
    
      // ...
    SysFreeString ( bstr );      
    

    注:1.string.c_str()只能转换成const char *:const char *c=aa.c_str();

      注意_bstr_t也提供char*和wchar_t*之间的转换操作符。这是一个值得怀疑的设计,因为即使它们是非常量字符串指针,你也一定不能使用这些指针去修改它们指向的缓冲区的内容,因为那将破坏内部的BSTR结构。

    2.cannot convert from 'const char *' to 'char *'
    3.要转成char *这样写:
     string mngName;
     char t[200];

    _variant_t
      _variant_t是一个对VARIANT的完整封装,它提供很多构造函数和转换函数来操作一个VARIANT可能包含的大量的数据类型。这里,我将只介绍与字符串有关的操作。

    memset(t,0,200);

    // Constructing
    _variant_t v1 = "char string";       // construct from a LPCSTR
    _variant_t v2 = L"wide char string"; // construct from a LPCWSTR
    _bstr_t bs1 = "Bob";
    _variant_t v3 = bs1;                 // copy from a _bstr_t object
    
    // Extracting data
    _bstr_t bs2 = v1;           // extract BSTR from the VARIANT
    _bstr_t bs3 = (_bstr_t) v1; // cast OK, same as previous line      
    

    strcpy(t,mngName.c_str());

    注意
      如果类型转换不能被执行,_variant_t方法能够抛出异常,所以应该准备捕获_com_error异常。

    BSTR转换成char*
    方法一:使用ConvertBSTRToString。例如:
      #include #pragma comment(lib, "comsupp.lib")
      int _tmain(int argc, _TCHAR* argv[])
      {
        BSTR bstrText = ::SysAllocString(L"Test");
        char* lpszText2 = _com_util::ConvertBSTRToString(bstrText);
        SysFreeString(bstrText);            // 用完释放
        delete[] lpszText2;
         return 0;
       }

    还需要注意的是
      没有从一个_variant_t变量到一个MBCS字符串的直接转换。你需要创建一个临时的_bstr_t变量,使用提供Unicode到MBCS转换的另一个字符串类或者使用一个ATL转换宏。
      不像_bstr_t,一个_variant_t变量可以被直接作为参数传递给一个COM方法。_variant_t
      继承自VARIANT类型,所以传递一个_variant_t来代替VARIANT变量是C++语言所允许的。

    方法二:使用_bstr_t的赋值运算符重载。例如:
    _bstr_t b = bstrText;
    char* lpszText2 = b;

    凤凰彩票官网app下载 5 STL 类
      STL只有一个字符串类,basic_string。一个basic_string管理一个以0做结束符的字符串数组。字符的类型是basic_string模般的参数。总的来说,一个basic_string类型的变量应该被当作不透明的对象。你可以得到一个指向内部缓冲区的只读指针,但是任何写操作必须使用basic_string的操作符和方法。
      basic_string有两个预定义的类型:包含char的string类型和包含wchar_t的wstring类型。这里没有内置的包含TCHAR的类型,但是你可以使用下面列出的代码来实现。

    char*转换成BSTR

    // Specializations
    typedef basic_string tstring; // string of TCHARs
    
    // Constructing
    string str = "char string";         // construct from a LPCSTR
    wstring wstr = L"wide char string"; // construct from a LPCWSTR
    tstring tstr = _T("TCHAR string");  // construct from a LPCTSTR
    
    // Extracting data
    LPCSTR psz = str.c_str();    // read-only pointer to str''s buffer
    LPCWSTR pwsz = wstr.c_str(); // read-only pointer to wstr''s buffer
    LPCTSTR ptsz = tstr.c_str(); // read-only pointer to tstr''s buffer
    

    方法一:使用SysAllocString等API函数。例如:
     BSTR bstrText = ::SysAllocString(L"Test");
     BSTR bstrText = ::SysAllocStringLen(L"Test",4);
     BSTR bstrText = ::SysAllocStringByteLen("Test",4);

      不像_bstr_t,一个basic_string变量不能在字符集之间直接转换。然而,你可以传递由c_str()返回的指针给另外一个类的构造函数(如果这个类的构造函数接受这种字符类型)。例如:

    方法二:使用COleVariant或_variant_t。例如:
    COleVariant strVar("This is a test");
    _variant_t strVar("This is a test");
    BSTR bstrText = strVar.bstrVal;

    // Example, construct _bstr_t from basic_string
    _bstr_t bs1 = str.c_str();  // construct a _bstr_t from a LPCSTR
    _bstr_t bs2 = wstr.c_str(); // construct a _bstr_t from a LPCWSTR      
    

    方法三,使用_bstr_t,这是一种最简单的方法。例如:
    BSTR bstrText = _bstr_t("This is a test");

    凤凰彩票官网app下载 6 ATL 类

    方法四,使用CComBSTR。例如:
    BSTR bstrText = CComBSTR("This is a test");

    CComBSTR
      CComBSTR 是 ATL 中的 BSTR 封装类,它在某些情况下比_bstr_t有用的多。最引人注意的是CComBSTR允许访问底层的BSTR,这意味着你可以传递一个CComBSTR对象给COM的方法。CComBSTR对象能够替你自动的管理BSTR的内存。例如,假设你想调用下面这个接口的方法:

    或CComBSTR bstr("This is a test");
    BSTR bstrText = bstr.m_str;

    // Sample interface:
    struct IStuff : public IUnknown
    {
      // Boilerplate COM stuff omitted...
      STDMETHOD(SetText)(BSTR bsText);
      STDMETHOD(GetText)(BSTR* pbsText);
    };      
    

    方法五,使用ConvertStringToBSTR。例如:
    char* lpszText = "Test";
    BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText);

      CComBSTR有一个操作符--BSTR方法,所以它能直接被传给SetText()函数。还有另外一个操作--&,这个操作符返回一个BSTR*。所以,你可以对一个CComBSTR对象使用&操作符,然后把它传给需要BSTR*参数的函数。

    CString转换成BSTR
    通常是通过使用CStringT::AllocSysString来实现。例如:
    CString str("This is a test");
    BSTR bstrText = str.AllocSysString();

    SysFreeString(bstrText); // 用完释放

    CComBSTR bs1;
    CComBSTR bs2 = "new text";
    
      pStuff->GetText ( &bs1 );       // ok, takes address of internal BSTR
      pStuff->SetText ( bs2 );        // ok, calls BSTR converter
      pStuff->SetText ( (BSTR) bs2 ); // cast ok, same as previous line      
    

    BSTR转换成CString
    一般可按下列方法进行:
    BSTR bstrText = ::SysAllocString(L"Test");
    CStringA str;
    str.Empty();
    str = bstrText;

      CComBSTR有和_bstr_t相似的构造函数,然而却没有内置的向MBCS字符串转换的函数。因此,你需要使用一个ATL转换宏。

    或CStringA str(bstrText);

    // Constructing
    CComBSTR bs1 = "char string";       // construct from a LPCSTR
    CComBSTR bs2 = L"wide char string"; // construct from a LPCWSTR
    CComBSTR bs3 = bs1;                 // copy from another CComBSTR
    CComBSTR bs4;
    
      bs4.LoadString ( IDS_SOME_STR );  // load string from string table
    // Extracting data
    BSTR bstr1 = bs1;        // returns internal BSTR, but don''t modify it!
    BSTR bstr2 = (BSTR) bs1; // cast ok, same as previous line
    BSTR bstr3 = bs1.Copy(); // copies bs1, returns it as a BSTR
    BSTR bstr4;
      bstr4 = bs1.Detach();  // bs1 no longer manages its BSTR
      // ...
      SysFreeString ( bstr3 );
      SysFreeString ( bstr4 );      
    

    ANSI、Unicode和宽字符之间的转换
    方法一:使用MultiByteToWideChar将ANSI字符转换成Unicode字符,

      注意在上个例子中使用了Detach()方法。调用这个方法后,CComBSTR对象不再管理它的BSTR字符串或者说它对应的内存。这就是bstr4需要调用SysFreeString()的原因。
      做一个补充说明:重载的&操作符意味着在一些STL容器中你不能直接使用CComBSTR变量,比如list。容器要求&操作符返回一个指向容器包含的类的指针,但是对CComBSTR变量使用&操作符返回的是BSTR*,而不是CComBSTR*。然而,有一个ATL类可以解决这个问题,这个类是CAdapt。例如,你可以这样声明一个CComBSTR的list:

    使用WideCharToMultiByte将Unicode字符转换成ANSI字符。
    方法二:使用“_T”将ANSI转换成“一般”类型字符串,使用“L”将ANSI转换成Unicode

    std::list< CAdapt<CComBSTR> > bstr_list;
    

    在托管C++环境中还可使用S将ANSI字符串转换成String*对象。

      CAdapt提供容器所需要的操作符,但这些操作符对你的代码是透明的。你可以把一个bstr_list当作一个CComBSTR的list来使用。

    例如:TCHAR tstr[] = _T("this is a test");
    wchar_t wszStr[] = L"This is a test";
    String* str = S”This is a test”;

    CComVariant
      CComVariant是VARIANT的封装类。然而,不像_variant_t,在CComVariant中VARIANT没有被隐藏。事实上你需要直接访问VARIANT的成员。CComVariant提供了很多构造函数来对VARIANT能够包含的多种类型进行处理。这里,我将只介绍和字符串相关的操作。

    方法三:使用ATL 7.0的转换宏和类。

    // Constructing
    CComVariant v1 = "char string";       // construct from a LPCSTR
    CComVariant v2 = L"wide char string"; // construct from a LPCWSTR
    CComBSTR bs1 = "BSTR bob";
    CComVariant v3 = (BSTR) bs1;          // copy from a BSTR
    
    // Extracting data
    CComBSTR bs2 = v1.bstrVal;            // extract BSTR from the VARIANT      
    

    ATL7.0在原有3.0基础上完善和增加了许多字符串转换宏以及提供相应的类:

      不像_variant_t,这里没有提供针对VARIANT包含的各种类型的转换操作符。正如上面介绍的,你必须直接访问VARIANT的成员并且确保这个VARIANT变量保存着你期望的类型。如果你需要把一个CComVariant类型的数据转换成一个BSTR类型的数据,你可以调用ChangeType()方法。

    其中,第一个C表示“类”,以便于ATL 3.0宏相区别,第二个C表示常量,2表示“to”,EX表示要开辟一定大小的缓冲。SourceType和DestinationType可以是A、 T、W和OLE,其含义分别是ANSI、Unicode、“一般”类型和OLE字符串。

    CComVariant v4 = ... // Init v4 from somewhere
    CComBSTR bs3;
    
      if ( SUCCEEDED( v4.ChangeType ( VT_BSTR ) ))
        bs3 = v4.bstrVal;      
    

    例如:CA2CT就是将ANSI转换成一般类型的字符串常量。下面是一些示例代码:
    LPTSTR tstr= CA2TEX<16>("this is a test");
    LPCTSTR tcstr= CA2CT("this is a test");
    wchar_t wszStr[] = L"This is a test";
    char* chstr = CW2A(wszStr);

      像_variant_t一样,CComVariant也没有提供向MBCS字符串转换的转换操作。你需要创建一个_bstr_t类型的中间变量,使用提供从Unicode到MBCS转换的另一个字符串类,或者使用一个ATL的转换宏。

     

    凤凰彩票官网app下载 7 ATL转换宏

    二.VC字符串转换(BSTR CString)

      ATL:转换宏是各种字符编码之间进行转换的一种很方便的方式,在函数调用时,它们显得非常有用。ATL转换宏的名称是根据下面的模式来命名的[源类型]2[新类型]或者[源类型]2C[新类型]。据有第二种形式的名字的宏的转换结果是常量指针(对应名字中的"C")。各种类型的简称如下:

     

    A: MBCS string, char* (A for ANSI)
    W: Unicode string, wchar_t* (W for wide)
    T: TCHAR string, TCHAR*
    OLE: OLECHAR string, OLECHAR* (in practice, equivalent to W)
    BSTR: BSTR (used as the destination type only)
    

    一.BSTR、LPSTR和LPWSTR

      所以,W2A()宏把一个Unicode字符串转换成一个MBCS字符串。T2CW()宏把一个TCHAR字符串转转成一个Unicode字符串常量。
      为了使用这些宏,需要先包含atlconv.h头文件。你甚至可以在非ATL工程中包含这个头文件来使用其中定义的宏,因为这个头文件独立于ATL中的其他部分,不需要一个_Module全局变量。当你在一个函数中使用转换宏时,需要把USES_CONVERSION宏放在函数的开头。它定义了转换宏所需的一些局部变量。
      当转换的目的类型是除了BSTR以外的其他类型时,被转换的字符串是存在栈中的。所以,如果你想让字符串的生命周期比当前的函数长,你需要把这个字符串拷贝到其他的字符串类中。当目的类型是BSTR时,内存不会自动被释放,你必须把返回值赋给一个BSTR变量或者一个BSTR封装类以避免内存泄漏。
      下面是一些各种转换宏的使用例子:

    在Visual C++.NET的所有编程方式中,我们常常要用到这样的一些基本字符串类型,如BSTR、LPSTR和LPWSTR等。之所以出现类似上述的这些数据类型,是因为不同编程语言之间的数据交换以及对ANSI、Unicode和多字节字符集(MBCS)的支持。

    // Functions taking various strings:
    void Foo ( LPCWSTR wstr );
    void Bar ( BSTR bstr );
    // Functions returning strings:
    void Baz ( BSTR* pbstr );
    #include <atlconv.h>
    main()
    {
    using std::string;
    USES_CONVERSION;    // declare locals used by the ATL macros
    // Example 1: Send an MBCS string to Foo()
    LPCSTR psz1 = "Bob";
    string str1 = "Bob";
    
      Foo ( A2CW(psz1) );
      Foo ( A2CW(str1.c_str()) );
    
    // Example 2: Send a MBCS and Unicode string to Bar()
    LPCSTR psz2 = "Bob";
    LPCWSTR wsz = L"Bob";
    BSTR bs1;
    CComBSTR bs2;
    
      bs1 = A2BSTR(psz2);         // create a BSTR
      bs2.Attach ( W2BSTR(wsz) ); // ditto, assign to a CComBSTR 
      Bar ( bs1 );
      Bar ( bs2 );
    
      SysFreeString ( bs1 );      // free bs1 memory
      // No need to free bs2 since CComBSTR will do it for us.
    
    // Example 3: Convert the BSTR returned by Baz()
    BSTR bs3 = NULL;
    string str2;
      Baz ( &bs3 );          // Baz() fills in bs3
      str2 = W2CA(bs3);      // convert to an MBCS string
      SysFreeString ( bs3 ); // free bs3 memory
    }      
    

    那么什么是BSTR、LPSTR以及LPWSTR呢?

      正如你所看见的,当你有一个和函数所需的参数类型不同的字符串时,使用这些转换宏是非常方便的。

    1.BSTR(Basic STRing,Basic字符串)是一个OLECHAR*类型的Unicode字符串。它被描述成一个与自动化相兼容的类型。由于操作系统提供相应的API函数(如SysAllocString)来管理它以及一些默认的调度代码,因此BSTR实际上就是一个COM字符串,但它却在自动化技术以外的多种场合下得到广泛使用。

    凤凰彩票官网app下载 8 MFC类

    2.LPSTR和LPWSTR是Win32和VC++所使用的一种字符串数据类型。LPSTR被定义成是一个指向以NULL(‘’)结尾的8位ANSI字符数组指针,而LPWSTR是一个指向以NULL结尾的16位双字节字符数组指针。在VC++中,还有类似的字符串类型,如LPTSTR、LPCTSTR等。

    CString
      因为一个MFC CString类的对象包含TCHAR类型的字符,所以确切的字符类型取决于你所定义的预处理符号。大体来说,CString 很像STL string,这意味着你必须把它当成不透明的对象,只能使用CString提供的方法来修改CString对象。CString有一个string所不具备的优点:CString具有接收MBCS和Unicode两种字符串的构造函数,它还有一个LPCTSTR转换符,所以你可以把CString对象直接传给一个接收LPCTSTR的函数而不需要调用c_str()函数。

    例如,LPCTSTR是指“long pointer to a constant generic string”,表示“一个指向一般字符串常量的长指针类型”,与C/C++的const char*相映射,而LPTSTR映射为 char*。

    // Constructing
    CString s1 = "char string";  // construct from a LPCSTR
    CString s2 = L"wide char string";  // construct from a LPCWSTR
    CString s3 ( '' '', 100 );  // pre-allocate a 100-byte buffer, fill with spaces
    CString s4 = "New window text";
    
      // You can pass a CString in place of an LPCTSTR:
      SetWindowText ( hwndSomeWindow, s4 );
    
      // Or, equivalently, explicitly cast the CString:
      SetWindowText ( hwndSomeWindow, (LPCTSTR) s4 );        
    

    一般地,还有下列类型定义:

      你可以从你的字符串表中装载一个字符串,CString的一个构造函数和LoadString()函数可以完成它。Format()方法能够从字符串表中随意的读取一个具有一定格式的字符串。     

    #ifdef UNICODE

    // Constructing/loading from string table
    CString s5 ( (LPCTSTR) IDS_SOME_STR );  // load from string table
    CString s6, s7; 
      // Load from string table.
      s6.LoadString ( IDS_SOME_STR );
    
      // Load printf-style format string from the string table:
      s7.Format ( IDS_SOME_FORMAT, "bob", nSomeStuff, ... );  
    

      typedef LPWSTR LPTSTR;

      第一个构造函数看起来有点奇怪,但是这实际上是文档说明的装入一个字符串的方法。 注意,对一个CString变量,你可以使用的唯一合法转换符是LPCTSTR。转换成LPTSTR(非常量指针)是错误的。养成把一个CString变量转换成LPTSTR的习惯将会给你带来伤害,因为当你的程序后来崩溃时,你可能不知道为什么,因为你到处都使用同样的代码而那时它们都恰巧正常工作。正确的得到一个指向缓冲区的非常量指针的方法是调用GetBuffer()方法。下面是正确的用法的一个例子,这段代码是给一个列表控件中的项设定文字:

      typedef LPCWSTR LPCTSTR;

    CString str = _T("new text");
    LVITEM item = {0};
      item.mask = LVIF_TEXT;
      item.iItem = 1;
      item.pszText = (LPTSTR)(LPCTSTR) str; // WRONG!
      item.pszText = str.GetBuffer(0);      // correct
    
      ListView_SetItem ( &item );
    str.ReleaseBuffer();  // return control of the buffer to str      
    

    #else

      pszText成员是一个LPTSTR变量,一个非常量指针,因此你需要对str调用GetBuffer()。GetBuffer()的参数是你需要CString为缓冲区分配的最小长度。如果因为某些原因,你需要一个可修改的缓冲区来存放1K TCHARs,你需要调用GetBuffer(1024)。把0作为参数时,GetBuffer()返回的是指向字符串当前内容的指针。
      上面划线的语句可以被编译,在这种情况下,甚至可以正常起作用。但这并不意味着这行代码是正确的。通过使用非常量转换,你已经破坏了面向对象的封装,并对CString的内部实现作了某些假定。如果你有这样的转换习惯,你终将会陷入代码崩溃的境地。你会想代码为什么不能正常工作了,因为你到处都使用同样的代码而那些代码看起来是正确的。
      你知道人们总是抱怨现在的软件的bug是多么的多吗?软件中的bug是因为程序员写了不正确的代码。难道你真的想写一些你知道是错误的代码来为所有的软件都满是bug这种认识做贡献吗?花些时间来学习使用CString的正确方法让你的代码在任何时间都正常工作把。
      CString 有两个函数来从一个 CString 创建一个 BSTR。它们是 AllocSysString() 和SetSysString()。

      typedef LPSTR LPTSTR;

    // Converting to BSTR
    CString s5 = "Bob!";
    BSTR bs1 = NULL, bs2 = NULL;
      bs1 = s5.AllocSysString();
      s5.SetSysString ( &bs2 );
      SysFreeString ( bs1 );
      SysFreeString ( bs2 );      
    

      typedef LPCSTR LPCTSTR;

    COleVariant
      COleVariant和CComVariant.很相似。COleVariant继承自VARIANT,所以它可以传给接收VARIANT的函数。然而,不像CComVariant,COleVariant只有一个LPCTSTR构造函数。没有对LPCSTR 和LPCWSTR的构造函数。在大多数情况下这不是一个问题,因为不管怎样你的字符串很可能是LPCTSTRs,但这是一个需要意识到的问题。COleVariant还有一个接收CString参数的构造函数。

    #endif

    // Constructing
    CString s1 = _T("tchar string");
    COleVariant v1 = _T("Bob"); // construct from an LPCTSTR
    COleVariant v2 = s1; // copy from a CString      
    

    二.CString、CStringA 和 CStringW

      像CComVariant一样,你必须直接访问VARIANT的成员。如果需要把VARIANT转换成一个字符串,你应该使用ChangeType()方法。然而,COleVariant::ChangeType()如果失败会抛出异常,而不是返回一个表示失败的HRESULT代码。

    Visual C++.NET中将CStringT作为ATL和MFC的共享的“一般”字符串类,它有CString、CStringA和CStringW三种形式,分别操作不同字符类型的字符串。这些字符类型是TCHAR、char和wchar_t。TCHAR在Unicode平台中等同于WCHAR(16位Unicode字符),在ANSI中等价于char。wchar_t通常定义为unsigned short。由于CString在MFC应用程序中经常用到,这里不再重复。

    // Extracting data
    COleVariant v3 = ...; // fill in v3 from somewhere
    BSTR bs = NULL;
      try
        {
        v3.ChangeType ( VT_BSTR );
        bs = v3.bstrVal;
        }
      catch ( COleException* e )
        {
        // error, couldn''t convert
        }
      SysFreeString ( bs );      
    

    三、VARIANT、COleVariant 和_variant_t

    凤凰彩票官网app下载 9 WTL 类

    在OLE、ActiveX和COM中,VARIANT数据类型提供了一种非常有效的机制,由于它既包含了数据本身,也包含了数据的类型,因而它可以实现各种不同的自动化数据的传输。下面让我们来看看OAIDL.H文件中VARIANT定义的一个简化版:

    CString
      WTL的CString的行为和MFC的 CString完全一样,所以你可以参考上面关于MFC的 CString的介绍。

    struct tagVARIANT {

    凤凰彩票官网app下载 10 CLR 和 VC 7 类

      VARTYPE vt;

      System::String是用来处理字符串的.NET类。在内部,一个String对象包含一个不可改变的字符串序列。任何对String对象的操作实际上都是返回了一个新的String对象,因为原始的对象是不可改变的。String的一个特性是如果你有不止一个String对象包含相同的字符序列,它们实际上是指向相同的对象的。相对于C++的使用扩展是增加了一个新的字符串常量前缀S,S用来代表一个受控的字符串常量(a managed string literal)。

      union {

    // Constructing
    String* ms = S"This is a nice managed string";      
    

       short iVal; // VT_I2.

      你可以传递一个非受控的字符串来创建一个String对象,但是样会比使用受控字符串来创建String对象造成效率的微小损失。这是因为所有以S作为前缀的相同的字符串实例都代表同样的对象,但这对非受控对象是不适用的。下面的代码清楚地阐明了这一点:

       long lVal; // VT_I4.

    String* ms1 = S"this is nice";
    String* ms2 = S"this is nice";
    String* ms3 = L"this is nice";
      Console::WriteLine ( ms1 == ms2 ); // prints true
      Console::WriteLine ( ms1 == ms3);  // prints false      
    

       float fltVal; // VT_R4.

    正确的比较可能没有使用S前缀的字符串的方法是使用String::CompareTo()

       double dblVal; // VT_R8.

      Console::WriteLine ( ms1->CompareTo(ms2) );
      Console::WriteLine ( ms1->CompareTo(ms3) );      
    

       DATE date; // VT_DATE.

      上面的两行代码都会打印0,0表示两个字符串相等。 String和MFC 7 CString之间的转换是很容易的。CString有一个向LPCTSTR的转换操作,而String有两个接收char* 和 wchar_t*的构造函数,因此你可以把一个CString变量直接传给一个String的构造函数。

       BSTR bstrVal; // VT_BSTR.

    CString s1 ( "hello world" );
    String* s2 ( s1 );  // copy from a CString      
    

       …

    反方向的转换也很类似

       short * piVal; // VT_BYREF|VT_I2.

    String* s1 = S"Three cats";
    CString s2 ( s1 );      
    

       long * plVal; // VT_BYREF|VT_I4.

      这也许会使你感到一点迷惑,但是它确实是起作用的。因为从VS.NET 开始,CString 有了一个接收String 对象的构造函数。

       float * pfltVal; // VT_BYREF|VT_R4.

      CStringT ( System::String* pString );      
    

       double * pdblVal; // VT_BYREF|VT_R8.

    对于一些快速操作,你可能想访问底层的字符串:

       DATE * pdate; // VT_BYREF|VT_DATE.

    String* s1 = S"Three cats";
      Console::WriteLine ( s1 );
    const __wchar_t __pin* pstr = PtrToStringChars(s1);
      for ( int i = 0; i < wcslen(pstr); i++ )
        (*const_cast<__wchar_t*>(pstr+i))++;
      Console::WriteLine ( s1 );      
    

       BSTR * pbstrVal; // VT_BYREF|VT_BSTR.

      PtrToStringChars()返回一个指向底层字符串的const __wchar_t* ,我们需要固定它,否则垃圾收集器或许会在我们正在管理它的内容的时候移动了它。

      };

    凤凰彩票官网app下载 11 在 printf-style 格式函数中使用字符串类

    };

      当你在printf()或者类似的函数中使用字符串封装类时你必须十分小心。这些函数包括sprintf()和它的变体,还有TRACE和ATLTRACE宏。因为这些函数没有对添加的参数的类型检查,你必须小心,只能传给它们C语言风格的字符串指针,而不是一个完整的字符串类。
      例如,要把一个_bstr_t 字符串传给ATLTRACE(),你必须使用显式转换(LPCSTR) 或者(LPCWSTR):

    显然,VARIANT类型是一个C结构,它包含了一个类型成员vt、一些保留字节以及一个大的union类型。例如,如果vt为VT_I2,那么我们可以从iVal中读出VARIANT的值。同样,当给一个VARIANT变量赋值时,也要先指明其类型。例如:

    _bstr_t bs = L"Bob!";
    ATLTRACE("The string is: %s in line %dn", (LPCSTR) bs, nLine);
    

    VARIANT va;

      如果你忘了使用转换符而把整个_bstr_t对象传给了函数,将会显示一些毫无意义的输出,因为_bstr_t保存的内部数据会全部被输出。

    :: VariantInit(&va); // 初始化

    凤凰彩票官网app下载 12 所有类的总结

    int a = 2002;

      两个字符串类之间进行转换的常用方式是:先把源字符串转换成一个C语言风格的字符串指针,然后把这个指针传递给目的类型的构造函数。下面这张表显示了怎样把一个字符串转换成一个C语言风格的字符串指针以及哪些类具有接收C语言风格的字符串指针的构造函数。

    va.vt = VT_I4; // 指明long数据类型

    Class 

    va.lVal = a; // 赋值

    string type

    为了方便处理VARIANT类型的变量,Windows还提供了这样一些非常有用的函数:

    convert to char*?

      VariantInit —— 将变量初始化为VT_EMPTY;

    convert to const char*?

      VariantClear —— 消除并初始化VARIANT;

    convert to wchar_t*?

      VariantChangeType —— 改变VARIANT的类型;

    convert to const wchar_t*?

      VariantCopy —— 释放与目标VARIANT相连的内存并复制源VARIANT。

    convert to BSTR?

      COleVariant类是对VARIANT结构的封装。它的构造函数具有极为强大大的功能,当对象构造时首先调用VariantInit进行初始化,然后根据参数中的标准类型调用相应的构造函数,并使用VariantCopy进行转换赋值操作,当VARIANT对象不在有效范围时,它的析构函数就会被自动调用,由于析构函数调用了VariantClear,因而相应的内存就会被自动清除。除此之外,COleVariant的赋值操作符在与VARIANT类型转换中为我们提供极大的方便。例如下面的代码:

    construct from char*?

    COleVariant v1("This is a test"); // 直接构造

    construct from wchar_t*?

    COleVariant v2 = "This is a test";

    _bstr_t

    // 结果是VT_BSTR类型,值为"This is a test"

    BSTR

    COleVariant v3((long)2002);

    yes cast1

    COleVariant v4 = (long)2002;

    yes cast

    // 结果是VT_I4类型,值为2002

    yes cast1

    _variant_t是一个用于COM的VARIANT类,它的功能与COleVariant相似。不过在Visual C++.NET的MFC应用程序中使用时需要在代码文件前面添加下列两句:

    yes cast

      #include "comutil.h"

    yes2

      #pragma comment( lib, "comsupp.lib" )

    yes

    四.CComBSTR和_bstr_t

    yes

    CComBSTR是对BSTR数据类型封装的一个ATL类,它的操作比较方便。例如:

    _variant_t

    CComBSTR bstr1;

    BSTR

    bstr1 = "Bye"; // 直接赋值

    no

    OLECHAR* str = OLESTR("ta ta");    // 长度为5的宽字符

    no

    CComBSTR bstr2(wcslen(str)) ;       // 定义长度为5

    no

    wcscpy(bstr2.m_str, str);             // 将宽字符串复制到BSTR中

    cast to
    _bstr_t3

    CComBSTR bstr3(5, OLESTR("Hello World"));

    cast to
    _bstr_t3

    CComBSTR bstr4(5, "Hello World");

    yes

    CComBSTR bstr5(OLESTR("Hey there"));

    yes

    CComBSTR bstr6("Hey there");

    string

    CComBSTR bstr7(bstr6);             // 构造时复制,内容为"Hey there"

    MBCS

    _bstr_t是是C++对BSTR的封装,它的构造和析构函数分别调用SysAllocString和SysFreeString函数,其他操作是借用BSTR API函数。与_variant_t相似,使用时也要添加comutil.h和comsupp.lib。

    no

    五.BSTR、char*和CString转换

    yes c_str() method

    (1) char*转换成CString

    no

    若将char*转换成CString,除了直接赋值外,还可使用CString::Format进行。例如:

    no

    char chArray[] = "This is a test";

    no

    char * p = "This is a test";

    yes

    或:LPSTR p = "This is a test";

    no

    或在已定义Unicode应的用程序中:TCHAR * p = _T("This is a test");

    wstring

    或:LPTSTR p = _T("This is a test");

    Unicode

    CString theString = chArray;

    no

    theString.Format(_T("%s"), chArray);

    no

    theString = p;

    no

    (2) CString转换成char*

    yes c_str() method

    若将CString类转换成char*(LPSTR)类型,常常使用下列三种方法:

    no

    方法一.使用强制转换。例如:

    no

    CString theString( "This is a test" );

    yes

    LPTSTR lpsz =(LPTSTR)(LPCTSTR)theString;

    CComBSTR

    方法二.使用strcpy。例如:

    BSTR

    CString theString( "This is a test" );

    no

    LPTSTR lpsz = new TCHAR[theString.GetLength()+1];

    no

    _tcscpy(lpsz, theString);

    no

     需要说明的是,strcpy(或可移值Unicode/MBCS的_tcscpy)的第二个参数是 const wchar_t* (Unicode)或const char* (ANSI),系统编译器将会自动对其进行转换。

    yes cast to BSTR

    方法三.使用CString::GetBuffer。例如:

    yes cast

    CString s(_T("This is a test "));

    yes

    LPTSTR p = s.GetBuffer();      // 在这里添加使用p的代码

    yes

    if(p != NULL) *p = _T('');

    CComVariant

    s.ReleaseBuffer();      // 使用完后及时释放,以便能使用其它的CString成员函数

    BSTR

    (3) BSTR转换成char*

    no

    方法一.使用ConvertBSTRToString。例如:

    no

    #include

    no

    #pragma comment(lib, "comsupp.lib")

    yes4

    int _tmain(int argc, _TCHAR* argv[])

    yes4

    {

    yes

    BSTR bstrText = ::SysAllocString(L"Test");

    yes

    char* lpszText2 = _com_util::ConvertBSTRToString(bstrText);

    CString

    SysFreeString(bstrText); // 用完释放

    TCHAR

    delete[] lpszText2;

    no6

    return 0;

    in MBCS
    builds, cast

    }

    no6

    方法二.使用_bstr_t的赋值运算符重载。例如:

    in Unicode
    builds, cast

    _bstr_t b = bstrText;

    no5

    char* lpszText2 = b;

    yes

    (4) char*转换成BSTR

    yes

    方法一.使用SysAllocString等API函数。例如:

    COleVariant

    BSTR bstrText = ::SysAllocString(L"Test");

    BSTR

    BSTR bstrText = ::SysAllocStringLen(L"Test",4);

    no

    BSTR bstrText = ::SysAllocStringByteLen("Test",4);

    凤凰彩票官网app下载,no

    方法二.使用COleVariant或_variant_t。例如:

    no

    //COleVariant strVar("This is a test");

    yes4

    _variant_t strVar("This is a test");

    yes4

    BSTR bstrText = strVar.bstrVal;

    in MBCS
    builds

    方法三.使用_bstr_t,这是一种最简单的方法。例如:

    in Unicode
    builds

    BSTR bstrText = _bstr_t("This is a test");

    1、即使 _bstr_t 提供了向非常量指针的转换操作符,修改底层的缓冲区也会已引起GPF如果你溢出了缓冲区或者造成内存泄漏。

    方法四.使用CComBSTR。例如:

    2、_bstr_t 在内部用一个 wchar_t* 来保存 BSTR,所以你可以使用 const wchar_t* 来访问BSTR。这是一个实现细节,你可以小心的使用它,将来这个细节也许会改变。

    BSTR bstrText = CComBSTR("This is a test");

    3、如果数据不能转换成BSTR会抛出一个异常。

    或CComBSTR bstr("This is a test");

    4、使用 ChangeType(),然后访问 VARIANT 的 bstrVal 成员。在MFC中,如果数据转换不成功将会抛出异常。

    BSTR bstrText = bstr.m_str;

    5、这里没有转换 BSTR 函数,然而 AllocSysString() 返回一个新的BSTR。

    方法五.使用ConvertStringToBSTR。例如:

    6、使用 GetBuffer() 方法,你可以暂时地得到一个非常量的TCHAR指针。

    char* lpszText = "Test";

     

    BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText);

    凤凰彩票官网app下载 13 **作者简介

    (5) CString转换成BSTR

    **Michael Dunn:   Michael Dunn居住在阳光城市洛杉矶。他是如此的喜欢这里的天气以致于想一生都住在这里。他在4年级时开始编程,那时用的电脑是Apple //e。1995年,在UCLA获得数学学士学位,随后在Symantec公司做QA工程师,在 Norton AntiVirus 组工作。他自学了 Windows 和 MFC 编程。1999-2000年,他设计并实现了 Norton AntiVirus的新界面。
      Michael 现在在 Napster(一个提供在线订阅音乐服务的公司)做开发工作,他还开发了UltraBar,一个IE工具栏插件,它可以使网络搜索更加容易,给了 googlebar 以沉重打击;他还开发了 CodeProject SearchBar;与人共同创建了 Zabersoft 公司,该公司在洛杉矶和丹麦的 Odense 都设有办事处。
      他喜欢玩游戏。爱玩的游戏有 pinball, bike riding,偶尔还玩 PS, Dreamcasth 和 MAME 游戏。他因忘了自己曾经学过的语言:法语、汉语、日语而感到悲哀。

    通常是通过使用CStringT::AllocSysString来实现。例如:

    Nishant S(Nish)
      Nish是来自印度 Trivandrum,的 Microsoft Visual C++ MVP。他从1990年开始编码。现在,Nish为作为合同雇员在家里为 CodeProject 工作。   
      他还写了一部浪漫戏剧《Summer Love and Some more Cricket》和一本编程书籍《Extending MFC applications with the .NET Framework》。他还管理者MVP的一个网站 。在这个网站上,你可以看到他的很多关于编程方面的思想和文章。
    Nish 还计划好了旅游,他希望自一生中能够到达地球上尽可能多的地方。

    CString str("This is a test");

    BSTR bstrText = str.AllocSysString();

    SysFreeString(bstrText); // 用完释放

    (6) BSTR转换成CString

    一般可按下列方法进行:

    BSTR bstrText = ::SysAllocString(L"Test");

    CStringA str;

    str.Empty();

    str = bstrText;

    或CStringA str(bstrText);

    (7) ANSI、Unicode和宽字符之间的转换

    方法一.使用MultiByteToWideChar将ANSI字符转换成Unicode字符,使用WideCharToMultiByte将Unicode字符转换成ANSI字符。

    方法二.使用“_T”将ANSI转换成“一般”类型字符串,使用“L”将ANSI转换成Unicode,而在托管C++环境中还可使用S将ANSI字符串转换成String*对象。例如:

    本文由凤凰彩票app下载发布于戏剧,转载请注明出处:CString-int-string-char-BSTR之间的转换

    关键词: