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

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

[复制链接]
发表于 2003-10-19 13:10:41 | 显示全部楼层 |阅读模式
2002-12-05· ·丁有和··yesky
" {/ l/ l; u- X" q5 E3 b. F9 ~8 o 4 }) W/ D) I0 z

5 C( S: }; y0 s$ K6 z/ ^  Visual C++.NET涉及到ATL/ATL Server、MFC和托管C++等多种编程方式,不仅功能强大而且应用广泛。在编程中,我们常常会遇到ANSI、Unicode以及BSTR不同编码类型的字符串转换操作。本文先介绍基本字符串类型,然后说明相关的类,如CComBSTR、_bstr_t、CStringT等,最后讨论它们的转换方法,其中还包括使用最新ATL7.0的转换类和宏,如CA2CT、CA2TEX等。3 J# R( N. K3 Q; d# k; ^$ d  a0 G0 s8 ]

/ U7 T, I7 E8 E! s% c" F& q0 e  一、BSTR、LPSTR和LPWSTR
! N/ i9 j. g5 F% l
! f8 ]0 q  l7 L! K, `: ]0 p0 U" B  在Visual C++.NET的所有编程方式中,我们常常要用到这样的一些基本字符串类型,如BSTR、LPSTR和LPWSTR等。之所以出现类似上述的这些数据类型,是因为不同编程语言之间的数据交换以及对ANSI、Unicode和多字节字符集(MBCS)的支持。
* h  y: N) P) q& W" j! L; k' E7 z: c% z% g$ p/ ~
  那么什么是BSTR、LPSTR以及LPWSTR呢?
6 b! f2 i3 n. `4 j0 g. E5 D/ t. B8 N; K& A' A
  BSTR(Basic STRing,Basic字符串)是一个OLECHAR*类型的Unicode字符串。它被描述成一个与自动化相兼容的类型。由于操作系统提供相应的API函数(如SysAllocString)来管理它以及一些默认的调度代码,因此BSTR实际上就是一个COM字符串,但它却在自动化技术以外的多种场合下得到广泛使用。图1描述了BSTR的结构,其中DWORD值是字符串中实际所占用的字节数,且它的值是字符串中Unicode字符的两倍。
, T. {1 l6 ~5 j# V0 ]
) Y( B: Z8 i" O$ H" e% e: ]4 C* [  LPSTR和LPWSTR是Win32和VC++所使用的一种字符串数据类型。LPSTR被定义成是一个指向以NULL(‘\0’)结尾的8位ANSI字符数组指针,而LPWSTR是一个指向以NULL结尾的16位双字节字符数组指针。在VC++中,还有类似的字符串类型,如LPTSTR、LPCTSTR等,它们的含义如图2所示。
8 S) O4 k5 _/ V% P; A; w$ p8 @# R8 ]
  j1 f( n1 B3 ]7 W8 H' _  例如,LPCTSTR是指“long pointer to a constant generic string”,表示“一个指向一般字符串常量的长指针类型”,与C/C++的const char*相映射,而LPTSTR映射为 char*。" I+ h  D+ h+ w
- B% a8 F' F9 y6 B8 G5 N* @
  一般地,还有下列类型定义:
3 W6 x4 b) j( R, p5 Q) j9 d8 ]6 ~1 o
#ifdef UNICODE ! J* Q  q: F' f
 typedef LPWSTR LPTSTR;
) T% `1 }: R: h$ k1 N, J typedef LPCWSTR LPCTSTR;
+ G4 v. p" G4 A) Z#else
% |+ M+ \" f. \* C typedef LPSTR LPTSTR;
" i2 A: J- Y* T/ U# E! e) p typedef LPCSTR LPCTSTR;
. H5 p* q; t( }# s  s#endif  7 u1 N/ C' E' t# w$ I; V! H

# N  \. l, n3 _1 |  二、CString、CStringA 和 CStringW' O& d+ j2 ?1 r$ J4 i( j

4 a- U# @8 B# J% {2 d% l. o  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应用程序中经常用到,这里不再重复。
% f5 ^, }. ^6 [$ p7 o$ h! i, P
  三、VARIANT、COleVariant 和_variant_t3 ~6 ?( F  I6 K8 T5 O! g! @
' K/ i! w) y, D3 J+ m  ?: E) ~
  在OLE、ActiveX和COM中,VARIANT数据类型提供了一种非常有效的机制,由于它既包含了数据本身,也包含了数据的类型,因而它可以实现各种不同的自动化数据的传输。下面让我们来看看OAIDL.H文件中VARIANT定义的一个简化版:; D1 u5 A1 f) Q: f3 T$ {) \

! J0 @* @; C2 l5 ystruct tagVARIANT {
( F% H( Y4 A% E& } VARTYPE vt;% F: H* }4 r/ @# v5 A2 O
 union {
. {8 N( t+ b5 _- E  short iVal; // VT_I2.$ p7 {" A# c# z9 Q& D
  long lVal; // VT_I4.* {4 f; W4 M3 P- Z8 Z  B
  float fltVal; // VT_R4.
! x/ j* }2 K9 H- b9 k  double dblVal; // VT_R8.
) }. G9 t; o; B6 v  DATE date; // VT_DATE.
' j6 e# g0 r/ _& U  BSTR bstrVal; // VT_BSTR.# P& @+ ^1 V0 f5 P% \
  …0 F0 C% |" u+ t* t+ z
  short * piVal; // VT_BYREF|VT_I2.
/ E  J$ R6 O1 j  long * plVal; // VT_BYREF|VT_I4.5 B) O8 L4 b6 j; {
  float * pfltVal; // VT_BYREF|VT_R4.
* d( N& p# {0 ?8 l+ w  double * pdblVal; // VT_BYREF|VT_R8.
/ ]" Y% H2 S) n, @( P5 r/ k& h0 c  DATE * pdate; // VT_BYREF|VT_DATE.8 }; D9 H& R  B" f+ r
  BSTR * pbstrVal; // VT_BYREF|VT_BSTR.
7 a/ {% p$ @/ p7 m) l* y };
+ V. F1 g% i# m1 [0 l* `};   A7 L8 a3 d4 I) h1 Z9 t; Q" u

6 j# E  `, R+ x/ ~  显然,VARIANT类型是一个C结构,它包含了一个类型成员vt、一些保留字节以及一个大的union类型。例如,如果vt为VT_I2,那么我们可以从iVal中读出VARIANT的值。同样,当给一个VARIANT变量赋值时,也要先指明其类型。例如:
6 y& O' D6 e' f% B  V& @2 I
. G4 C* V6 r$ |5 hVARIANT va;
* _/ i  ]2 |1 j; \- f/ S2 ~:: VariantInit(&va); // 初始化0 Q' g" ?( f' J( E% w
int a = 2002;
# A' s! ^& e! A  t1 E3 R, M$ m$ Vva.vt = VT_I4; // 指明long数据类型& D* s2 T' c8 r% a7 Z: O
va.lVal = a; // 赋值 : L/ j9 n$ x+ z
7 u2 o, D) [5 K& z7 G2 u- X
  为了方便处理VARIANT类型的变量,Windows还提供了这样一些非常有用的函数:
- a. V3 j2 h, ]: _
% [2 s1 @5 q$ E* |( J  VariantInit —— 将变量初始化为VT_EMPTY;& v2 ]- U& ?) \: q

4 e0 _7 o" }5 k1 Z- K  VariantClear —— 消除并初始化VARIANT;/ T; \1 z0 c1 v6 u7 R- T6 d, K

1 T3 k7 X( d) a  VariantChangeType —— 改变VARIANT的类型;6 x7 b* M& }# k9 t
2 V! O; e  Y5 A2 [( `
  VariantCopy —— 释放与目标VARIANT相连的内存并复制源VARIANT。
+ Y9 [1 V- b0 T+ h3 e7 P/ v
: c  \4 a9 F  R* X+ _  COleVariant类是对VARIANT结构的封装。它的构造函数具有极为强大大的功能,当对象构造时首先调用VariantInit进行初始化,然后根据参数中的标准类型调用相应的构造函数,并使用VariantCopy进行转换赋值操作,当VARIANT对象不在有效范围时,它的析构函数就会被自动调用,由于析构函数调用了VariantClear,因而相应的内存就会被自动清除。除此之外,COleVariant的赋值操作符在与VARIANT类型转换中为我们提供极大的方便。例如下面的代码:% Q( N; H2 ^; E5 y

4 z9 K) j* V; l5 a. LCOleVariant v1("This is a test"); // 直接构造
; o, i! A4 u% K2 bCOleVariant v2 = "This is a test"; % V9 S" c4 j& a* F, @- Q( |
// 结果是VT_BSTR类型,值为"This is a test"
: D" V. _+ D5 R' l+ [COleVariant v3((long)2002);5 u- ^2 F9 r. a) U5 s4 D
COleVariant v4 = (long)2002;
$ c- C) @* ^8 J// 结果是VT_I4类型,值为2002
- [8 B' ]* Q5 @/ g0 w0 |2 ?
7 J' x( I. o" q5 s8 _  _variant_t是一个用于COM的VARIANT类,它的功能与COleVariant相似。不过在Visual C++.NET的MFC应用程序中使用时需要在代码文件前面添加下列两句:# U: z- ]& |: G! n) m, k
7 \; P1 z2 s7 t* `+ ?
  #include "comutil.h"
& }9 O& b* _+ S3 N* H5 U
& J2 m7 l, v2 L/ M8 R( x  \  #pragma comment( lib, "comsupp.lib" )! g( L+ ^6 y; R

' {6 n/ Y( b' J* h4 a0 p  四、CComBSTR和_bstr_t
% ?& s+ F# ]" W3 B8 m  j( l8 ]. d% ?2 `- f# b0 H
  CComBSTR是对BSTR数据类型封装的一个ATL类,它的操作比较方便。例如:
( y* u+ F3 P) @' Y* J) b( ^& r+ `6 D4 ?- x5 Y3 b4 `) }
CComBSTR bstr1;
. h4 q9 B3 M- Xbstr1 = "Bye"; // 直接赋值; p( w* K4 `) `7 e3 y7 G# q
OLECHAR* str = OLESTR("ta ta"); // 长度为5的宽字符/ |. X' M9 a+ y: Q" G& Q  j
CComBSTR bstr2(wcslen(str)); // 定义长度为5
3 `" G( s$ F. {4 j* s, `wcscpy(bstr2.m_str, str); // 将宽字符串复制到BSTR中
. o0 F# Z6 @, t  j1 Z* dCComBSTR bstr3(5, OLESTR("Hello World")); . @9 Q3 ]1 f6 N, T
CComBSTR bstr4(5, "Hello World"); ) c/ B* X4 T& ~7 [) w4 a
CComBSTR bstr5(OLESTR("Hey there")); & y( F4 U4 S* C1 z' l9 B. S
CComBSTR bstr6("Hey there"); 5 i, h7 X# T$ [, J/ G; ^/ c
CComBSTR bstr7(bstr6); + n; _, b. z% e- `* R2 X: E8 _9 N3 r$ y
// 构造时复制,内容为"Hey there" ) {( f  B4 B' ^
. k+ w, g8 m* z! Z0 Q5 H7 |  P' F
  _bstr_t是是C++对BSTR的封装,它的构造和析构函数分别调用SysAllocString和SysFreeString函数,其他操作是借用BSTR API函数。与_variant_t相似,使用时也要添加comutil.h和comsupp.lib。
2 a% m0 G0 M$ U1 G2 \
  v7 o, @8 J# _7 q/ u  五、BSTR、char*和CString转换3 A' l- G# P" k8 E$ W# Q

4 y/ W4 W, D  {  (1) char*转换成CString
; X8 f1 c/ ]' Q9 h& L7 l
3 s5 T: a. K% C2 Y; J" I+ s$ J  若将char*转换成CString,除了直接赋值外,还可使用CString::Format进行。例如:' e; [8 L0 Q! e/ C* v# |
& W5 E9 a- N. I5 P) w
char chArray[] = "This is a test";
" p( w3 Y! s& H9 n- q) \char * p = "This is a test";
1 `$ u1 |  T8 O( c9 Z5 c3 e/ Z# |  e8 R' T) S( S* S* d
  或; q% N4 `0 p$ X) T

& y" O% e& J% P7 w! HLPSTR p = "This is a test"; - M$ q( D6 b9 X' s3 _! H8 e

) w2 g4 R6 p5 t: K  或在已定义Unicode应的用程序中8 e$ M+ C4 ^; i; S8 O
' ^; R1 O6 y0 v6 ~- G
TCHAR * p = _T("This is a test");
1 \1 A5 P0 [3 {, X! h3 Q2 w' ]9 g3 W1 D# v$ H
  或% H/ F" }" g& ]; m
3 A' Z# g. o. M$ P
LPTSTR p = _T("This is a test");
( K7 m  `* [0 J* Q# YCString theString = chArray;
$ f+ w7 P9 A% F4 m, q. m" ktheString.Format(_T("%s"), chArray);8 S4 e: c) O3 i: l) ~
theString = p; ! Z( \, @3 I0 q/ M. `. Y1 V

. r. J) h. ?7 C8 Y: `# G: `  (2) CString转换成char*
$ s1 y6 G6 B6 W: A
6 i+ a1 @+ G; p9 p3 ?& X  若将CString类转换成char*(LPSTR)类型,常常使用下列三种方法:
% \2 ]0 X( u6 n, J9 C! T9 a+ {! h/ `8 W: }8 L1 r- q3 s$ t2 B
  方法一,使用强制转换。例如:
- X5 Y, X, h" a( I
) O" p1 R8 I% S3 t9 u1 x# iCString theString( "This is a test" );) ?6 c& Z# F$ r  _# s, p
LPTSTR lpsz =(LPTSTR)(LPCTSTR)theString;  
6 P2 |7 Z: U. t: A) u" A* T( U4 J; W/ L5 R. q& P! w" V
  方法二,使用strcpy。例如:2 q, A0 u; C* Y/ v$ P, |4 C- t

$ }: b. Y! U/ B' p" h$ D8 PCString theString( "This is a test" );3 _  C$ Z( @( r! m
LPTSTR lpsz = new TCHAR[theString.GetLength()+1];  U1 c3 I% F% L6 Y% P
_tcscpy(lpsz, theString); : a# ?8 E+ d) E3 h/ b
; ?$ G. K1 L0 a: s0 E! Q
  需要说明的是,strcpy(或可移值Unicode/MBCS的_tcscpy)的第二个参数是 const wchar_t* (Unicode)或const char* (ANSI),系统编译器将会自动对其进行转换。9 ]6 H8 B0 y7 C) {

9 m0 M' V) s) _9 u; I% o  方法三,使用CString::GetBuffer。例如:
- F9 o+ E! |- h0 v& g1 R0 J
% T: `, v, S3 j( v  J8 B( j% s1 k' eCString s(_T("This is a test "));1 u+ D, `, h8 Q" z) ]6 B
LPTSTR p = s.GetBuffer();0 w6 E( t: R$ A
// 在这里添加使用p的代码8 g8 `& A8 l& b  Q3 j" I" _( o( L
if(p != NULL) *p = _T('\0');% E+ x! U$ d' R6 C' H7 u, M- T  ^
s.ReleaseBuffer(); 4 s1 H0 m1 c/ t$ M" `' b
// 使用完后及时释放,以便能使用其它的CString成员函数
  Q' E) A) a: C$ b7 y' P
8 X6 `3 Y: u6 M4 Z- |) j  (3) BSTR转换成char*
7 M" P% {9 y9 y; }2 \; a! F
& ^( G' Y9 I% A* A  方法一,使用ConvertBSTRToString。例如:( M; n7 B0 X2 F, F" C) o
. `4 y9 X. w& d* G- r2 D  M
#include
/ T1 N# ~: C. ]: ]: l; V6 u" x#pragma comment(lib, "comsupp.lib")% m+ r3 @0 y8 w, r( P
int _tmain(int argc, _TCHAR* argv[]){; G1 K. x! o5 Q9 `; c) H  e" u
BSTR bstrText = ::SysAllocString(L"Test");; K, B1 }3 z  p
char* lpszText2 = _com_util::ConvertBSTRToString(bstrText);
! J1 y* o4 Z9 kSysFreeString(bstrText); // 用完释放6 |; \- F- C  I
delete[] lpszText2;& N5 V* @( D1 P( x
return 0;8 z& @9 i" j' d" M$ k
}  & G! i; R' \+ _: }% N9 b" X
' l: E+ J5 X7 Z
  方法二,使用_bstr_t的赋值运算符重载。例如:
1 x0 |9 j/ p5 W) k0 X! _7 B# F& F( ~/ q. O0 f
_bstr_t b = bstrText;/ V3 E$ R5 A: F$ z
char* lpszText2 = b; ; w3 Y$ v. g6 p( o# k# Z4 W

5 u! u4 \; L5 M3 l  (4) char*转换成BSTR
. K6 K' M6 ?* z' P( m; m3 u) q$ |; @/ A+ t
  方法一,使用SysAllocString等API函数。例如:: }, C4 t. O; @$ V3 B3 e% b
- F) b0 z! W' X' V( R
BSTR bstrText = ::SysAllocString(L"Test");
# i; N' b0 p# a, p6 nBSTR bstrText = ::SysAllocStringLen(L"Test",4);
! M( F3 T7 u; R' H% ^BSTR bstrText = ::SysAllocStringByteLen("Test",4);
: D5 x& |: z6 c7 l  p" o& n. `7 i7 {) R! O. W2 C& M: F
  方法二,使用COleVariant或_variant_t。例如:
" l; \: ?, _" I  E) t
9 g6 x7 o2 E* ?* w//COleVariant strVar("This is a test");
/ l9 u9 N, a3 e  H, c! `_variant_t strVar("This is a test");
2 K' U) x! g# X# a  `6 ?BSTR bstrText = strVar.bstrVal;
: b. @1 D( Z2 g6 _) x% |
/ f/ P# R" M  p  方法三,使用_bstr_t,这是一种最简单的方法。例如:
2 S* u* f6 r$ j" z3 d
+ Y- J6 ^: c2 \7 TBSTR bstrText = _bstr_t("This is a test"); . E7 i8 [8 q/ A0 Z1 L
3 L8 P2 O- r& |3 G: s( A
  方法四,使用CComBSTR。例如:- @) @: b- A9 z" X

: |* p% [2 f. Q+ vBSTR bstrText = CComBSTR("This is a test"); , o. a$ k+ {) x+ v

: r3 O- O6 B. u9 t  或
, E" q* `# j: O" P* R) T1 A  S5 P& c7 _
CComBSTR bstr("This is a test");
& @; B1 Q6 F3 EBSTR bstrText = bstr.m_str;
  |- q2 Q; r' q5 a9 y" @6 M! k4 p& I& g
  方法五,使用ConvertStringToBSTR。例如:
* T, W1 P# d8 _- n, n  V9 }
2 {  M" L5 h! j5 [0 C4 O& \, q2 _+ pchar* lpszText = "Test";% s: ^$ N+ B' Q$ F% v+ V' E
BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText);
* @" b  a* s; W' d* z8 O3 \/ c$ u) I3 Q
  (5) CString转换成BSTR- K( r+ R/ R; Y; [

0 O0 H$ o( ^1 j" m; o  通常是通过使用CStringT::AllocSysString来实现。例如:2 B9 m0 h3 ~' L7 D  j  j) J  h

: j( z( p- C# d% c( T& O; F  t; ?CString str("This is a test");
9 @- R) d  Q5 S4 c7 E5 }; W* \BSTR bstrText = str.AllocSysString();
! ?+ Y$ c5 u. o1 n9 p8 c% a# C% K+ y5 ]' s/ u
SysFreeString(bstrText); // 用完释放  
' ], F- Q1 _! l8 C" K: g% U9 K# `6 o# o* I8 E$ ^! c
  (6) BSTR转换成CString
. P& C1 L' J, [6 ~' U( i6 J( L  {
  一般可按下列方法进行:
( ]  B+ [  [. [" p+ l* G0 k% O8 v# l: f8 c! q  B/ z7 L
BSTR bstrText = ::SysAllocString(L"Test");% p* H2 t8 F( Q! s. F  z; l
CStringA str;
# N. o, s2 I* [& }str.Empty();+ y" z6 ], S* w  I4 d
str = bstrText;  
. |% U, [/ b9 d/ D2 [; Y8 }- a, w- }, e/ P3 V2 R
  或, G- U# m' I5 ?* G% r
+ r1 h; d! [6 h* {5 z: t
CStringA str(bstrText);
' V  V2 W; v! ]- J5 ^; z* o
3 _" Y$ r2 |; O8 \5 I+ {  (7) ANSI、Unicode和宽字符之间的转换& s) m! u9 v$ u; c3 J+ j
( Z$ y, F- g  e
  方法一,使用MultiByteToWideChar将ANSI字符转换成Unicode字符,使用WideCharToMultiByte将Unicode字符转换成ANSI字符。
0 r: Y0 T  ^) A) K8 m# C9 w  o. N" Z9 z- X% L
  方法二,使用“_T”将ANSI转换成“一般”类型字符串,使用“L”将ANSI转换成Unicode,而在托管C++环境中还可使用S将ANSI字符串转换成String*对象。例如:
( c' p. `9 }& K" q( b0 Z* Z# J, x6 [5 I  Z
TCHAR tstr[] = _T("this is a test");! Y: s% ?+ g1 \) v# [1 I
wchar_t wszStr[] = L"This is a test";; m6 p7 S( C' ~* U9 q" [9 q# l
String* str = S”This is a test”;
' B7 v! Y) p8 j+ k( [8 ^( F3 L; e' I+ W0 i, ^7 Q
  方法三,使用ATL 7.0的转换宏和类。ATL7.0在原有3.0基础上完善和增加了许多字符串转换宏以及提供相应的类,它具有如图3所示的统一形式:& W% [1 O8 v" [8 I# z

9 t  i, Z" f: f( e  其中,第一个C表示“类”,以便于ATL 3.0宏相区别,第二个C表示常量,2表示“to”,EX表示要开辟一定大小的缓冲。SourceType和DestinationType可以是A、T、W和OLE,其含义分别是ANSI、Unicode、“一般”类型和OLE字符串。例如,CA2CT就是将ANSI转换成一般类型的字符串常量。下面是一些示例代码:2 T! M) |' h5 g* m% f& j9 c4 i5 L

; W* A2 d4 N5 `$ \LPTSTR tstr= CA2TEX<16>("this is a test");4 T  n. @. K# k/ Q& F
LPCTSTR tcstr= CA2CT("this is a test");& S: j8 @1 e  ~% |7 u7 v: j
wchar_t wszStr[] = L"This is a test";
6 t( q2 Q1 u( s* zchar* chstr = CW2A(wszStr);  
2 Z7 S8 F& |; r5 x
1 v9 E8 W: o( i: v5 j/ H) |0 ]  六、结语% r" w, ]8 c! `! \; }- `

5 s+ o7 j9 e9 D. ^$ q  几乎所有的程序都要用到字符串,而Visual C++.NET由于功能强大、应用广泛,因而字符串之间的转换更为频繁。本文几乎涉及到目前的所有转换方法。当然对于.NET框架来说,还可使用Convert和Text类进行不同数据类型以及字符编码之间的相互转换。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2026-6-18 14:17 , Processed in 0.019223 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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