找回密码
 注册
搜索
查看: 4580|回复: 0

Visual C++.NET中的字符串转换方法

[复制链接]
发表于 2003-10-19 13:10:41 | 显示全部楼层 |阅读模式
2002-12-05· ·丁有和··yesky
/ ~; P" k( N5 q$ W/ c2 T 3 I; \5 v0 I& e0 h( ^5 a/ u* V$ y, o* E

% z& k) d6 k4 l/ g5 y  Visual C++.NET涉及到ATL/ATL Server、MFC和托管C++等多种编程方式,不仅功能强大而且应用广泛。在编程中,我们常常会遇到ANSI、Unicode以及BSTR不同编码类型的字符串转换操作。本文先介绍基本字符串类型,然后说明相关的类,如CComBSTR、_bstr_t、CStringT等,最后讨论它们的转换方法,其中还包括使用最新ATL7.0的转换类和宏,如CA2CT、CA2TEX等。
0 p/ P8 C5 S: n" Z. T9 Y$ c
6 u! D  f& u/ q2 S" K, L* {' `  一、BSTR、LPSTR和LPWSTR2 b) Y; R# ]2 @9 K3 L
& B4 d; U* x2 _- J
  在Visual C++.NET的所有编程方式中,我们常常要用到这样的一些基本字符串类型,如BSTR、LPSTR和LPWSTR等。之所以出现类似上述的这些数据类型,是因为不同编程语言之间的数据交换以及对ANSI、Unicode和多字节字符集(MBCS)的支持。
; r2 p, x9 }9 o6 J  V4 J/ j" u! d. T* f5 w, t
  那么什么是BSTR、LPSTR以及LPWSTR呢?1 V* r# b& v/ S2 J
6 x9 I8 \* J/ T% h& g4 q' l
  BSTR(Basic STRing,Basic字符串)是一个OLECHAR*类型的Unicode字符串。它被描述成一个与自动化相兼容的类型。由于操作系统提供相应的API函数(如SysAllocString)来管理它以及一些默认的调度代码,因此BSTR实际上就是一个COM字符串,但它却在自动化技术以外的多种场合下得到广泛使用。图1描述了BSTR的结构,其中DWORD值是字符串中实际所占用的字节数,且它的值是字符串中Unicode字符的两倍。
5 y1 o8 {- i: m
/ D& I" ]; G$ d  o% E  LPSTR和LPWSTR是Win32和VC++所使用的一种字符串数据类型。LPSTR被定义成是一个指向以NULL(‘\0’)结尾的8位ANSI字符数组指针,而LPWSTR是一个指向以NULL结尾的16位双字节字符数组指针。在VC++中,还有类似的字符串类型,如LPTSTR、LPCTSTR等,它们的含义如图2所示。, ~: s8 l" {7 M7 l* e  l0 I7 Z
2 ~; Z3 J4 V! c. J; Q0 l
  例如,LPCTSTR是指“long pointer to a constant generic string”,表示“一个指向一般字符串常量的长指针类型”,与C/C++的const char*相映射,而LPTSTR映射为 char*。
5 i, g9 P% U" U* q, `4 Q. x$ ]+ ~% t- q5 \) q0 p
  一般地,还有下列类型定义:
4 f. e* P" D: b1 z$ L$ j. G9 H8 E2 X4 x" h: n' ]
#ifdef UNICODE + |9 i" X' U+ h- Q0 r
 typedef LPWSTR LPTSTR;! R7 U' z8 Q, X- X
 typedef LPCWSTR LPCTSTR;
3 l* g, Q& I: V; R3 {#else
) e' `6 g- L; P# j typedef LPSTR LPTSTR;
" a+ o# r% O. ?& j* l typedef LPCSTR LPCTSTR; 5 v9 ^# L- s8 {6 A9 n5 H
#endif  ! r& o1 B) z9 o
, Y5 [0 _' T, L$ q9 g: r
  二、CString、CStringA 和 CStringW7 I6 F# Q0 E  _% y1 N5 Y, p
0 ~: i" _1 ?/ a) s" ~  v
  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应用程序中经常用到,这里不再重复。0 K  O4 }) s2 z. ?* t4 h

! N7 b" \: P4 S# d3 Z  三、VARIANT、COleVariant 和_variant_t
, s: j* n7 B6 G3 e& c( E7 S6 h; a% ~. Q& {- m/ `# C
  在OLE、ActiveX和COM中,VARIANT数据类型提供了一种非常有效的机制,由于它既包含了数据本身,也包含了数据的类型,因而它可以实现各种不同的自动化数据的传输。下面让我们来看看OAIDL.H文件中VARIANT定义的一个简化版:! o2 f$ V' r! F* C& x! D
' b; r5 z' o8 A, g
struct tagVARIANT {
" g) F8 D4 y0 |/ R( g# @8 S  a& |/ O VARTYPE vt;8 K3 a! g  f( P+ T9 ?4 F
 union {* V6 I$ t: @4 h# T$ m) D
  short iVal; // VT_I2.! ^0 W0 {7 e: H% j, m+ [. G
  long lVal; // VT_I4.
5 ^$ [& D+ P# l5 ~7 h. W  float fltVal; // VT_R4.
0 \2 F( J9 @2 C$ l" Y2 Q  double dblVal; // VT_R8.
7 {# G" W- ^; _- U7 y$ p  DATE date; // VT_DATE.' y+ Z) C$ `# u/ ~- {6 z
  BSTR bstrVal; // VT_BSTR.; V% Q+ w# K6 k2 f3 o
  …
! E: G) P0 H$ a, `1 }" ]  short * piVal; // VT_BYREF|VT_I2.) g% u. ~( x  ^. l. I. i6 n  m4 a
  long * plVal; // VT_BYREF|VT_I4.5 S7 i; p! H$ |+ W5 k
  float * pfltVal; // VT_BYREF|VT_R4.
8 I* G7 j( `2 ]( J2 u  double * pdblVal; // VT_BYREF|VT_R8.) N) a0 m% U( M) W/ |
  DATE * pdate; // VT_BYREF|VT_DATE.
2 W% L. D$ m- [- \$ N: b' t/ b  BSTR * pbstrVal; // VT_BYREF|VT_BSTR.
% b9 j4 e' x* V9 P' b };; Z! q; j; N1 G7 [% }
};
9 Q3 a  e! v3 d7 c/ q- M
% C! ]$ T- n9 j1 `: j  显然,VARIANT类型是一个C结构,它包含了一个类型成员vt、一些保留字节以及一个大的union类型。例如,如果vt为VT_I2,那么我们可以从iVal中读出VARIANT的值。同样,当给一个VARIANT变量赋值时,也要先指明其类型。例如:# @  `8 k/ u9 y% e
4 m4 D* c; B9 ~
VARIANT va;- P, ]' ?; ?$ }* n, o6 @
:: VariantInit(&va); // 初始化
4 i1 h0 }/ A) `1 z( R: ^int a = 2002;
+ ~) C) e  T  }# gva.vt = VT_I4; // 指明long数据类型( F4 `( d" y" \, q
va.lVal = a; // 赋值
6 s# U, x) X" E6 G* N8 |# X2 G$ m6 A( `3 H$ z+ E
  为了方便处理VARIANT类型的变量,Windows还提供了这样一些非常有用的函数:" @& n( Z) r' b9 {+ w4 b  z

$ V/ D" I% k. d" r  VariantInit —— 将变量初始化为VT_EMPTY;6 x7 H& b. {1 _! W( G' |
4 @0 Y  j9 Z, s$ @
  VariantClear —— 消除并初始化VARIANT;) D, C! m7 k2 c8 F& A" H- P7 R) @

: a7 H# S' u- u! H4 y# G  VariantChangeType —— 改变VARIANT的类型;: C( d! j7 F& Y7 a) c! x% f. M; F2 i! D" A& H
7 e6 W) p' d2 w; j8 u+ E- X: ]
  VariantCopy —— 释放与目标VARIANT相连的内存并复制源VARIANT。/ Q8 ^6 R2 b! X

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

* t$ @% H4 W+ @) SCOleVariant v1("This is a test"); // 直接构造
1 h6 ~5 g- Q. u9 }/ q) n, h! ZCOleVariant v2 = "This is a test"; , N3 A) H( B7 Z6 u  l) \. r: S
// 结果是VT_BSTR类型,值为"This is a test"
: g+ c0 f: }: l% z4 S2 j3 XCOleVariant v3((long)2002);# o) X3 K. t$ I
COleVariant v4 = (long)2002;6 l5 y) p0 l6 R, S( m
// 结果是VT_I4类型,值为2002
) T4 J9 E' B, f+ P& \
5 `7 A" o- v9 \  y) F- W2 p  _variant_t是一个用于COM的VARIANT类,它的功能与COleVariant相似。不过在Visual C++.NET的MFC应用程序中使用时需要在代码文件前面添加下列两句:- B, R" r- R6 x! p' y- e# W) D
1 b' A+ b9 l6 l3 P$ |$ V
  #include "comutil.h"
( l7 s3 `) q* q! o  ?8 t. N2 c% P5 ?+ O, z) r9 u/ d; C- d
  #pragma comment( lib, "comsupp.lib" )5 q6 E5 ?/ D3 |  d1 `' |

! V7 A" T; z. t% X% g$ n  四、CComBSTR和_bstr_t8 b: m8 V& p) |1 O' c
# d8 b( e0 b7 n- j2 ]6 F+ F
  CComBSTR是对BSTR数据类型封装的一个ATL类,它的操作比较方便。例如:$ ], {, b& ~6 _# W  I: D3 U  W
5 ]8 R. c1 x* u/ k  M4 |
CComBSTR bstr1;
& d2 _  ^/ k7 Zbstr1 = "Bye"; // 直接赋值
0 u* Q0 X8 R' E% h, s" K0 O. ^' |  r% WOLECHAR* str = OLESTR("ta ta"); // 长度为5的宽字符: ?. M5 W  U7 D& r! I& s; t
CComBSTR bstr2(wcslen(str)); // 定义长度为5: N) |: T$ J* ]' Z2 R
wcscpy(bstr2.m_str, str); // 将宽字符串复制到BSTR中
6 }# A3 K- @0 S8 U1 s1 {4 V  Y9 yCComBSTR bstr3(5, OLESTR("Hello World")); 1 \6 b: K, f% \* a, |4 K3 t
CComBSTR bstr4(5, "Hello World"); , l6 }: K* }( X' c2 m
CComBSTR bstr5(OLESTR("Hey there")); / [& P3 T. A  k9 q& L6 \
CComBSTR bstr6("Hey there"); - q: r$ h9 {) q, \
CComBSTR bstr7(bstr6); " ]2 S3 g& Z8 |- U  g. q; q: V$ H
// 构造时复制,内容为"Hey there" $ ^( e- h2 ~* n8 V8 H: n
$ _8 |7 m1 c2 r2 a- b( G  R6 A7 b
  _bstr_t是是C++对BSTR的封装,它的构造和析构函数分别调用SysAllocString和SysFreeString函数,其他操作是借用BSTR API函数。与_variant_t相似,使用时也要添加comutil.h和comsupp.lib。2 o/ U" F* b' V; Z1 V1 g
) l3 R( ^  G# h1 S
  五、BSTR、char*和CString转换) T6 N! W9 P3 b) r% w- n; s( N* }
+ P* ^" }6 B. a9 D
  (1) char*转换成CString
- l( U  R) ]/ T2 @8 s4 k# y) @3 g! P" c9 v# x1 X
  若将char*转换成CString,除了直接赋值外,还可使用CString::Format进行。例如:
. @) c2 X/ O- N& Y! o9 G
& x/ \, }  j+ g: L" k* R" T- echar chArray[] = "This is a test";3 T4 X3 w- g( W/ ]! A5 d
char * p = "This is a test"; : l1 @  w/ y# b/ R) D1 I& N8 w
8 R7 @( E5 A2 h% Z
  或
# ~, `4 f  T1 G! H& N! u: W' B2 X" |$ y: m# p& t# A/ h& e1 z% q  f5 Z
LPSTR p = "This is a test"; ; X  v9 u% G" [

& \) O  p8 L# ^, f3 T  或在已定义Unicode应的用程序中
8 I; g. G7 G1 O- ^
" @8 @. R, k5 U" e0 J6 V  BTCHAR * p = _T("This is a test"); 9 ~, s- @, K) Q) j" h) `, D6 ^, \! g& z4 ]

4 a. @  B4 ?& E1 j4 }0 ?1 L  或% H. m& F6 q5 J* n9 l
. \8 r4 `" n9 t$ ?. W4 n
LPTSTR p = _T("This is a test");
5 V' `  J: r$ fCString theString = chArray;4 X3 g. N$ Y0 }
theString.Format(_T("%s"), chArray);
, d# a- S5 e7 I! |! ^8 otheString = p; 1 N) B4 j, f  t7 M. J
2 u- D8 p0 |5 b# P% j
  (2) CString转换成char*
% l8 ~3 d1 ^, S. d2 z9 C% @* P4 c  Q3 T2 Y% p5 H! S, R
  若将CString类转换成char*(LPSTR)类型,常常使用下列三种方法:
2 u0 u) [. m5 }+ N0 c! r* D8 E5 \- \* [% y0 f9 e3 A* s. j
  方法一,使用强制转换。例如:/ M( g' ~# D! S3 f! b: H" o
7 S' }+ x# f! F! r
CString theString( "This is a test" );8 z# @9 G( z! k9 s) x+ q: q$ w
LPTSTR lpsz =(LPTSTR)(LPCTSTR)theString;  1 g& p4 E$ M. F0 \! `

, c* e" r4 m2 h2 }( N  方法二,使用strcpy。例如:' }5 Y, i5 V6 W
! i2 o7 ]) L/ ^( E5 H" A
CString theString( "This is a test" );0 o' ^" ]) ~! Y$ J7 S8 B& [
LPTSTR lpsz = new TCHAR[theString.GetLength()+1];
+ h  E% @0 W+ I! q9 f_tcscpy(lpsz, theString);
% ]( e% \. ~' j' H: }$ f" }7 B( P3 R6 j
  需要说明的是,strcpy(或可移值Unicode/MBCS的_tcscpy)的第二个参数是 const wchar_t* (Unicode)或const char* (ANSI),系统编译器将会自动对其进行转换。
! i2 ?7 d9 ]4 S; |- u; M8 M- o4 s6 Y2 s$ D" g
  方法三,使用CString::GetBuffer。例如:
3 x8 J" m  ?9 e( ^
/ [' ?* M' W' m" v$ P5 E- LCString s(_T("This is a test "));
7 r9 u' }1 W( @- N- D2 i: ~0 a" ], e! GLPTSTR p = s.GetBuffer();
/ f+ u5 U6 m! f& T( p7 }  |' a// 在这里添加使用p的代码
! G0 N0 U. x; C$ Y. Qif(p != NULL) *p = _T('\0');& c0 I. E8 r! Z- m" b) B
s.ReleaseBuffer();
- W5 S& H7 A' U2 r. Y# Q6 {// 使用完后及时释放,以便能使用其它的CString成员函数 9 s$ t. f& [8 r! L
- ]' `2 h9 {  ~# r3 A" O$ W, F
  (3) BSTR转换成char*1 P$ j- y' ?& I7 _  M+ o. j

- C- A1 j; L9 _) `- F4 I  方法一,使用ConvertBSTRToString。例如:8 [4 @, U* ~7 b1 X5 k1 k  r

0 o1 k6 {% D2 D3 L#include / P4 T( \/ g+ g7 B
#pragma comment(lib, "comsupp.lib")
! C) z: c4 u6 M0 ]+ `int _tmain(int argc, _TCHAR* argv[]){0 y" [% E4 u8 a  H% g  j
BSTR bstrText = ::SysAllocString(L"Test");
! ?# X' V% v0 g2 i: U  Achar* lpszText2 = _com_util::ConvertBSTRToString(bstrText);  X7 m6 {) [0 h- ?7 n% a
SysFreeString(bstrText); // 用完释放- c$ Q: e1 K0 R+ h3 Q
delete[] lpszText2;
* A' w$ D, [# [! ^  Freturn 0;
" @: `1 H/ `" S& @}  
8 _$ F! a0 L/ p; k* ?. Y: Q9 K4 s1 ]9 G
  方法二,使用_bstr_t的赋值运算符重载。例如:
2 W/ b/ r( n. E" z$ q
" h( o& p, n! u- E0 l7 P! C_bstr_t b = bstrText;
- ~" ]0 E" s. Wchar* lpszText2 = b; & F# y+ L+ z, w4 n( C9 j

, a' \1 I' B6 H- {  (4) char*转换成BSTR
) _  L; H3 v* y' Y3 K$ N. t% P8 H7 e- r1 N5 A& d* c; _* h( n- f. D! Y
  方法一,使用SysAllocString等API函数。例如:
, @* j4 A3 \  P5 M" c' C2 [' d. A/ T
BSTR bstrText = ::SysAllocString(L"Test");
: N* @% F8 ~1 K$ N2 _* F2 |5 b3 QBSTR bstrText = ::SysAllocStringLen(L"Test",4);/ `5 G" Q' n5 V' y
BSTR bstrText = ::SysAllocStringByteLen("Test",4);
: v" [$ p5 k; i: u6 q( n) E' J/ V! V: k* h1 t
  方法二,使用COleVariant或_variant_t。例如:
6 V: L* ^- r$ S6 |' Z! Z: c: g4 z( J6 E$ W! Z7 n
//COleVariant strVar("This is a test");! W, c+ t* K" h
_variant_t strVar("This is a test");
2 g: }7 b4 O" S+ X0 o% a3 {BSTR bstrText = strVar.bstrVal;
& b4 ]+ c* K/ o3 u& Z* O3 H: V  x5 ?* q, u1 T1 b( Q& M
  方法三,使用_bstr_t,这是一种最简单的方法。例如:5 w! l$ Q$ r0 S/ B  v

4 i  ~* \: \! q- x( s/ sBSTR bstrText = _bstr_t("This is a test"); 7 w& g8 n2 {9 {* Y2 y+ X
3 a4 u5 n% M8 Y9 P$ n( p
  方法四,使用CComBSTR。例如:+ _# {+ n' E( @

  @) k3 t& k5 y  O7 E# x; VBSTR bstrText = CComBSTR("This is a test");
, I% ?3 M' F& X4 S4 v& C( m+ |
; l5 ?* D) A# L8 y* M- s# v" _  或
* q  J* D4 `0 P7 q6 T1 u: O. J4 K5 `* v* I$ V1 Y# I( F
CComBSTR bstr("This is a test");$ K! G& f, X: }5 O& W3 v: c5 {1 ?
BSTR bstrText = bstr.m_str; , |, x; R2 H* o' \  W* s

4 D4 w* K% T" s7 R  方法五,使用ConvertStringToBSTR。例如:
7 O. T* Q+ l7 g; E3 M9 f; z! V. O3 ~( L8 h* P# A
char* lpszText = "Test";
' N- M% ~6 z; o8 S" R  wBSTR bstrText = _com_util::ConvertStringToBSTR(lpszText);
9 x6 b6 t1 ~1 \. |; J- r
+ W1 u5 @" \3 }: b1 s  (5) CString转换成BSTR
" h6 J' o' f" p; \
4 d1 k; p, @( ~+ s/ Y6 @( e) |  通常是通过使用CStringT::AllocSysString来实现。例如:" N2 d# W- }) O# _  k
% ]5 ?% U' B# \" y
CString str("This is a test");
' T2 q) a& D: l$ ~: {/ S: M3 V; [BSTR bstrText = str.AllocSysString();' Z1 S1 }' ]5 f$ S
. {; M! F- i" v  p1 T3 K
SysFreeString(bstrText); // 用完释放  
# @1 w* j1 G5 ]2 |. T
( e" Q0 `) |6 s( z# W3 L2 V  (6) BSTR转换成CString* |5 k0 L6 G/ m% {

& q8 O! J( ?5 G! t  一般可按下列方法进行:
5 ~+ M7 c+ @+ Q" L% e! S) V+ u2 S. J5 Q
BSTR bstrText = ::SysAllocString(L"Test");
% w% B7 L6 e8 P" a6 VCStringA str;6 o0 f# D. j2 W1 j
str.Empty();
0 O2 h9 I5 R, l* j4 I5 p9 {str = bstrText;  ; s! h% z/ w  p6 h

' \# F  D! \! T3 p$ ~$ f2 P  或
9 G7 M3 f- R  `, c9 I0 c; Y. V4 O# A
CStringA str(bstrText);
2 B, X. I0 t9 m
/ z3 ]; w0 G' E; ^5 }  (7) ANSI、Unicode和宽字符之间的转换* K9 k9 ?, }3 r' C6 w1 g/ b) p

& a: g" ?- ]2 D' f/ v  方法一,使用MultiByteToWideChar将ANSI字符转换成Unicode字符,使用WideCharToMultiByte将Unicode字符转换成ANSI字符。' E' q+ T5 A8 w4 y; c3 ?# o+ `# K
& Y+ K$ O, Q2 ^. {6 C  L9 [% w
  方法二,使用“_T”将ANSI转换成“一般”类型字符串,使用“L”将ANSI转换成Unicode,而在托管C++环境中还可使用S将ANSI字符串转换成String*对象。例如:& ]9 C: G3 J; O5 s6 U* Q
) z- V% ]+ I1 R5 q8 `
TCHAR tstr[] = _T("this is a test");
( t1 G& n$ e! cwchar_t wszStr[] = L"This is a test";& H3 z) i0 u" E$ {, w7 ?
String* str = S”This is a test”;
  L6 ~; ]6 A0 X9 c# B4 Q8 a+ K- o" @- S
  方法三,使用ATL 7.0的转换宏和类。ATL7.0在原有3.0基础上完善和增加了许多字符串转换宏以及提供相应的类,它具有如图3所示的统一形式:
; e: V" O. T8 E+ V
) ^! S$ d; k" `6 ~. }0 O  其中,第一个C表示“类”,以便于ATL 3.0宏相区别,第二个C表示常量,2表示“to”,EX表示要开辟一定大小的缓冲。SourceType和DestinationType可以是A、T、W和OLE,其含义分别是ANSI、Unicode、“一般”类型和OLE字符串。例如,CA2CT就是将ANSI转换成一般类型的字符串常量。下面是一些示例代码:
9 X0 f8 ^& Z% q% y: B# D" F! z, X2 u% `
LPTSTR tstr= CA2TEX<16>("this is a test");
* h( w+ _- ]- _& \& g' QLPCTSTR tcstr= CA2CT("this is a test");
; O+ O  b: w' ?: y9 @# ]wchar_t wszStr[] = L"This is a test";5 B5 s9 H! J5 {3 ~/ C7 X1 {
char* chstr = CW2A(wszStr);  2 {. o/ B- L0 H/ e

( x$ I! ^& d8 [' _/ y/ _% z" n  六、结语
; P, e" U1 H/ T: P" ^% h! i5 L
  几乎所有的程序都要用到字符串,而Visual C++.NET由于功能强大、应用广泛,因而字符串之间的转换更为频繁。本文几乎涉及到目前的所有转换方法。当然对于.NET框架来说,还可使用Convert和Text类进行不同数据类型以及字符编码之间的相互转换。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|宁德市腾云网络科技有限公司 ( 闽ICP备2022007940号-5|闽公网安备 35092202000206号 )

GMT+8, 2026-5-2 08:56 , Processed in 0.018253 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表