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

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

[复制链接]
发表于 2003-10-19 13:10:41 | 显示全部楼层 |阅读模式
2002-12-05· ·丁有和··yesky
, z8 i# o2 {* U2 v' z4 c3 |8 Y# E
3 I) n8 `; Q8 r& |3 Y  t4 B( d) c: V! f) C0 s3 i' `5 ?3 ]
  Visual C++.NET涉及到ATL/ATL Server、MFC和托管C++等多种编程方式,不仅功能强大而且应用广泛。在编程中,我们常常会遇到ANSI、Unicode以及BSTR不同编码类型的字符串转换操作。本文先介绍基本字符串类型,然后说明相关的类,如CComBSTR、_bstr_t、CStringT等,最后讨论它们的转换方法,其中还包括使用最新ATL7.0的转换类和宏,如CA2CT、CA2TEX等。' W0 u' O# F1 `8 \* j* w' M3 a0 z

; ]. Q* h5 p! _/ p- H  一、BSTR、LPSTR和LPWSTR. l4 m! f4 n' m- F1 ?. y" U" g
# V7 a9 n  k) z" L2 @  R& J
  在Visual C++.NET的所有编程方式中,我们常常要用到这样的一些基本字符串类型,如BSTR、LPSTR和LPWSTR等。之所以出现类似上述的这些数据类型,是因为不同编程语言之间的数据交换以及对ANSI、Unicode和多字节字符集(MBCS)的支持。
2 K4 ^6 _5 i0 K& P# [/ [# i" h8 R! r0 g: P( Z
  那么什么是BSTR、LPSTR以及LPWSTR呢?) v" c  _1 N8 W6 D

- d1 l; @+ q  g0 N; _3 k  BSTR(Basic STRing,Basic字符串)是一个OLECHAR*类型的Unicode字符串。它被描述成一个与自动化相兼容的类型。由于操作系统提供相应的API函数(如SysAllocString)来管理它以及一些默认的调度代码,因此BSTR实际上就是一个COM字符串,但它却在自动化技术以外的多种场合下得到广泛使用。图1描述了BSTR的结构,其中DWORD值是字符串中实际所占用的字节数,且它的值是字符串中Unicode字符的两倍。9 M& _; e6 w$ L9 ^' D* f1 \: H
7 d' ?8 P8 b: U/ h
  LPSTR和LPWSTR是Win32和VC++所使用的一种字符串数据类型。LPSTR被定义成是一个指向以NULL(‘\0’)结尾的8位ANSI字符数组指针,而LPWSTR是一个指向以NULL结尾的16位双字节字符数组指针。在VC++中,还有类似的字符串类型,如LPTSTR、LPCTSTR等,它们的含义如图2所示。
/ _# ^# ~( y3 J3 U% J- C9 a$ N  W3 C  F" b$ N- q! F
  例如,LPCTSTR是指“long pointer to a constant generic string”,表示“一个指向一般字符串常量的长指针类型”,与C/C++的const char*相映射,而LPTSTR映射为 char*。
2 K7 R+ k% U: u. J/ @% ]. j! ^; j3 s7 B! q5 j! w
  一般地,还有下列类型定义:
' j, u% l2 y- V2 d8 G; m7 r- R6 U7 D$ R
#ifdef UNICODE
1 m6 P' V% e& P* M3 M* i2 K; o" g typedef LPWSTR LPTSTR;
4 M, R: @& N# a+ h, V: r typedef LPCWSTR LPCTSTR;
3 F% L) G* Q1 R. p: c#else ( b5 }" d, _9 ?2 M1 H: o0 M0 Z* s
 typedef LPSTR LPTSTR;
+ y% ~# S( P. T, Q$ U typedef LPCSTR LPCTSTR; - ?; {9 M; S: u( y% J1 g
#endif  
$ u! `3 }  H3 u+ m( ~* _/ e  @& b8 C! {0 f
  二、CString、CStringA 和 CStringW3 h% ]5 N4 Z; T4 W2 X

5 K6 O% j+ |6 }- A! U# _! t7 @7 Q  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应用程序中经常用到,这里不再重复。
' r/ W1 \2 L; W2 {( w, }3 h1 w0 s1 q$ g2 f
  三、VARIANT、COleVariant 和_variant_t) i; y% W4 G0 Z' j
% [, Q  \# _; W% I" w9 ^( k
  在OLE、ActiveX和COM中,VARIANT数据类型提供了一种非常有效的机制,由于它既包含了数据本身,也包含了数据的类型,因而它可以实现各种不同的自动化数据的传输。下面让我们来看看OAIDL.H文件中VARIANT定义的一个简化版:
3 c" Z5 ^& B# o$ ]3 a/ s. p/ K! ]: b* J# q, y& X3 G2 m/ `
struct tagVARIANT {
0 c: O2 k, |0 F/ q5 Q* p VARTYPE vt;
& x( J" @6 s  c( p union {
% r) e* B& w2 H, T+ ~9 }: I  short iVal; // VT_I2.9 }6 C, r) ^% P8 j  e7 ~* z
  long lVal; // VT_I4.1 v) I/ H7 w1 I) @2 p
  float fltVal; // VT_R4." m9 \0 O  w, r) [' m% |
  double dblVal; // VT_R8.# S, ]8 ?" s  N9 e5 S. K4 ?9 \
  DATE date; // VT_DATE.
4 F/ V: g) ]: V: U  BSTR bstrVal; // VT_BSTR.
& J( y" d( a# m- |0 g' _* y  …
+ u  v* k9 Q$ A& c1 j  short * piVal; // VT_BYREF|VT_I2.. G; C, X0 Z& D( j2 \: |+ F* s
  long * plVal; // VT_BYREF|VT_I4.
( x4 U! l" J$ `# n1 g  Y  float * pfltVal; // VT_BYREF|VT_R4.0 m6 I8 @8 C+ l" C4 R6 P' b+ w. b( b
  double * pdblVal; // VT_BYREF|VT_R8.5 N2 _# f1 u/ Q- i4 H' v0 p7 T
  DATE * pdate; // VT_BYREF|VT_DATE.
5 \+ t( \4 R6 a2 {  a6 {% O# f4 ~1 S& ]( C  BSTR * pbstrVal; // VT_BYREF|VT_BSTR.
. y) S+ E9 D: d8 ^" M, k9 ?* y };1 D9 @9 n, l7 r
}; ) l6 z$ G; U' a" f! d" G

; ?& Y* U6 m, A. S  |* j4 S  显然,VARIANT类型是一个C结构,它包含了一个类型成员vt、一些保留字节以及一个大的union类型。例如,如果vt为VT_I2,那么我们可以从iVal中读出VARIANT的值。同样,当给一个VARIANT变量赋值时,也要先指明其类型。例如:  [% m( r  U3 t7 P6 a
& k. f& E8 T1 y# ]5 J8 x1 M5 w
VARIANT va;
8 O. a6 K4 V  u* j:: VariantInit(&va); // 初始化  G. E" t; }( F7 @  A9 r6 w
int a = 2002;& W- s5 Y( I8 _* i) r
va.vt = VT_I4; // 指明long数据类型8 n3 V7 Y: x) H- I: j8 J
va.lVal = a; // 赋值 8 @1 N  C/ m2 s
. v# H7 H# d9 u5 ?# O" E. [$ g
  为了方便处理VARIANT类型的变量,Windows还提供了这样一些非常有用的函数:
0 a- J: t% v+ @" u2 X  o
, G- A% b- |/ H4 y7 x# d  VariantInit —— 将变量初始化为VT_EMPTY;
9 \9 b  Q, R8 m" d; V/ a, U: U/ J2 T9 T# y
  VariantClear —— 消除并初始化VARIANT;! p/ v8 T/ q2 _+ q
# |% O: |8 i' u5 v
  VariantChangeType —— 改变VARIANT的类型;% v$ I/ f1 c+ [, x  _* K

9 j# Q* b( ~- N' ~, a  VariantCopy —— 释放与目标VARIANT相连的内存并复制源VARIANT。+ p# |8 q% C- K4 p1 o9 _/ A6 P
5 }& Y8 e" o% P
  COleVariant类是对VARIANT结构的封装。它的构造函数具有极为强大大的功能,当对象构造时首先调用VariantInit进行初始化,然后根据参数中的标准类型调用相应的构造函数,并使用VariantCopy进行转换赋值操作,当VARIANT对象不在有效范围时,它的析构函数就会被自动调用,由于析构函数调用了VariantClear,因而相应的内存就会被自动清除。除此之外,COleVariant的赋值操作符在与VARIANT类型转换中为我们提供极大的方便。例如下面的代码:' c) L2 \3 q, {6 ~8 d
/ h+ {! y1 {7 A+ M9 ]+ }% z  \
COleVariant v1("This is a test"); // 直接构造
& g& Y, O9 U$ s) BCOleVariant v2 = "This is a test"; ( }( ?3 v5 Z$ l6 _+ o( ~
// 结果是VT_BSTR类型,值为"This is a test"7 v! ~7 `4 `' |  r, r& E, i
COleVariant v3((long)2002);6 a: q$ B) ], ^4 l6 X
COleVariant v4 = (long)2002;
3 ~/ a; v" u3 ^& Y+ m, a// 结果是VT_I4类型,值为2002
% L4 v9 g' F  U/ w: J0 A* P7 X# }/ `. ?# I$ S' V5 [1 s7 W
  _variant_t是一个用于COM的VARIANT类,它的功能与COleVariant相似。不过在Visual C++.NET的MFC应用程序中使用时需要在代码文件前面添加下列两句:
, l$ O8 c3 G4 L4 u% c+ _2 o7 z6 w
  #include "comutil.h"
6 n* K* |% S9 m5 H1 l2 C
" y" {: [3 j) }2 Q) q/ I  #pragma comment( lib, "comsupp.lib" )
. B. ~5 d3 @4 O* e& w3 m9 _" N0 i2 X% u6 R7 D' d1 k4 G8 ?
  四、CComBSTR和_bstr_t  F) g" O6 H9 T, t% ]
1 ^3 j3 g+ |1 A- }0 J$ q% c
  CComBSTR是对BSTR数据类型封装的一个ATL类,它的操作比较方便。例如:. a3 S% y4 l6 k4 p

! B" _) R& Y0 E: q) c8 S7 N. P) kCComBSTR bstr1;
" R6 i  v/ n6 J  I% [0 Tbstr1 = "Bye"; // 直接赋值
4 R2 ^+ Y% G$ rOLECHAR* str = OLESTR("ta ta"); // 长度为5的宽字符8 Y: N7 {: S5 h
CComBSTR bstr2(wcslen(str)); // 定义长度为5
* u3 Q" w5 Q3 d* Rwcscpy(bstr2.m_str, str); // 将宽字符串复制到BSTR中
' u, o- h0 V# B" F! I9 gCComBSTR bstr3(5, OLESTR("Hello World")); 1 w, o, G$ G. R9 ^: w; h9 e/ K
CComBSTR bstr4(5, "Hello World"); 7 {5 v' k. }  d8 h. H, a4 o5 F# j" U
CComBSTR bstr5(OLESTR("Hey there"));
) h( p* {& r! M6 [CComBSTR bstr6("Hey there"); % T3 e6 F# U' Q6 N
CComBSTR bstr7(bstr6); 5 Z$ ?6 o" {; m. D- M/ ^
// 构造时复制,内容为"Hey there"
9 X" F( W  S! X$ U1 j
9 z. J5 I5 a! @  _bstr_t是是C++对BSTR的封装,它的构造和析构函数分别调用SysAllocString和SysFreeString函数,其他操作是借用BSTR API函数。与_variant_t相似,使用时也要添加comutil.h和comsupp.lib。
/ b3 {8 m. n# F) c5 S$ O. w4 j
' ~5 O( U; t7 H  五、BSTR、char*和CString转换
' X% o" Z9 p  R: f* U
2 a/ S/ p$ b3 c! c5 v, H$ i6 h  (1) char*转换成CString
( I, n8 w2 q8 N) G) b1 Y2 S1 n$ o' y
  若将char*转换成CString,除了直接赋值外,还可使用CString::Format进行。例如:
: ^5 U: L1 a; B5 A) b6 X
3 z: P6 X  C& `3 o0 [1 X  c: tchar chArray[] = "This is a test";
/ t# O; t  q4 z/ c. m3 B9 L5 W+ x) Ochar * p = "This is a test";
$ c! g. Z" A: D1 c/ l- e1 ~5 z
$ E! d1 D5 J4 q' E! B- A  或) J8 A7 x4 Q% f/ A5 W: O  \

% t% t1 M6 s- i) `" `$ C$ tLPSTR p = "This is a test";
" N* A- W$ ~" `& P  i2 ^7 M9 k  u7 c' b3 h
  或在已定义Unicode应的用程序中( N- v, ]) `: w' V' `' o( B5 n
( W0 M* O/ G" M  ^0 a$ V1 |
TCHAR * p = _T("This is a test"); 0 L( W- V$ G: x
% K, p: J+ Q. S! |. Z
  或. M+ y  ~7 z. e$ ?0 M+ }
$ I! I* G/ F" E1 I+ V
LPTSTR p = _T("This is a test");
% {* ?4 W, z& R  G/ cCString theString = chArray;
# \7 @2 f6 s5 q/ _3 y  f4 \$ l7 I, htheString.Format(_T("%s"), chArray);
/ z, A$ q1 t: i# ~theString = p;
' [& l( ]7 }5 a3 \4 s4 R
8 i( B5 O8 Q7 j& b( s; Q  (2) CString转换成char*
- Q: \* C& H9 q) b/ y7 f/ L$ o) g" G8 \4 ]5 e) X( ^( e9 {3 L1 |
  若将CString类转换成char*(LPSTR)类型,常常使用下列三种方法:
8 u% x. t( r3 c
, I( W: `8 M+ k& w# Q3 i# ]! |8 a  方法一,使用强制转换。例如:+ ^6 V; K/ _( p; G, J6 I9 m
" @) i2 a; D( V
CString theString( "This is a test" );/ S. C5 k6 w! C
LPTSTR lpsz =(LPTSTR)(LPCTSTR)theString;  . |- t" `: C7 ]  y0 f' V% W
- X! z, C$ c7 R  A- i5 f
  方法二,使用strcpy。例如:, d+ I1 y. v+ H* x- c( |
; V: Y4 o) @( N3 g1 n" s1 ]
CString theString( "This is a test" );
  v' B7 H/ u2 O% @" CLPTSTR lpsz = new TCHAR[theString.GetLength()+1];
# j2 X7 e  R  w* {7 Z) m_tcscpy(lpsz, theString);
. m0 W; c. o( I' \  ~5 v6 m- m( `' {/ n5 U
  需要说明的是,strcpy(或可移值Unicode/MBCS的_tcscpy)的第二个参数是 const wchar_t* (Unicode)或const char* (ANSI),系统编译器将会自动对其进行转换。
( g* n  h, c; s. H# V" m% L6 `, o
8 }  s/ U& B% G4 z  方法三,使用CString::GetBuffer。例如:
  e; w# p5 F$ o  d5 \
3 C2 r: Z' K/ p; [CString s(_T("This is a test "));
' b7 f: L+ g( O6 p4 oLPTSTR p = s.GetBuffer();2 @: a1 [$ ?1 j
// 在这里添加使用p的代码
" c. h3 B* c: ]/ D% v, {if(p != NULL) *p = _T('\0');
6 C* s% l2 H0 @+ ^4 W3 a, Os.ReleaseBuffer(); . c6 j0 l- L- |" v3 x! r
// 使用完后及时释放,以便能使用其它的CString成员函数
* [6 n! Z* y4 p8 I0 c* y2 _) ?+ _' Z* @8 u3 I0 m, z. K! b
  (3) BSTR转换成char*
- A+ s; _$ w2 |" v3 f: c$ g7 c2 ^" X; t$ U/ v4 t
  方法一,使用ConvertBSTRToString。例如:' t  E+ H  i& E% }! ~

, i! _( X+ U: J; G9 |#include
0 o! f3 X8 y7 S7 o( ~( _, g& j* Y#pragma comment(lib, "comsupp.lib")
& ?1 x. m4 \( l% G& Hint _tmain(int argc, _TCHAR* argv[]){
1 w( A8 z6 R! e7 g9 BBSTR bstrText = ::SysAllocString(L"Test");
. I+ m5 P4 j! O9 ]char* lpszText2 = _com_util::ConvertBSTRToString(bstrText);
2 h$ C/ j9 M- i) r2 A% tSysFreeString(bstrText); // 用完释放2 p# }2 ~: r7 s# _" P* h- x7 P
delete[] lpszText2;
' l" H& f, v2 S/ }! nreturn 0;8 Y; t3 Y! W& r, N
}  
( i9 a7 a. @) c( D+ ?  o; A2 K( ?. U& Z5 u
  方法二,使用_bstr_t的赋值运算符重载。例如:
( D3 `; p3 e2 T: M: [
; G( U; P3 F  }7 Q( ?  O9 t$ b0 \_bstr_t b = bstrText;
! V8 \' U( V# pchar* lpszText2 = b;
& p. U9 E+ G1 i8 h
3 j/ q- P5 C& E& E2 f" \/ ?/ u  (4) char*转换成BSTR
: d; F0 j" y3 y
& x' q! N' _1 P  方法一,使用SysAllocString等API函数。例如:  @* q! K- `8 x) y" q$ ^5 s

: e& m; @# T) L) o" D# J: _: KBSTR bstrText = ::SysAllocString(L"Test");. o4 @, T+ [+ C$ x$ W0 g1 p
BSTR bstrText = ::SysAllocStringLen(L"Test",4);2 Y+ a6 t, \; c1 j
BSTR bstrText = ::SysAllocStringByteLen("Test",4);
9 L& H8 S" A  d8 p( E7 s! ?/ E1 p' {+ E+ O0 i. I
  方法二,使用COleVariant或_variant_t。例如:
" j0 _+ S9 ]* x/ }4 N7 a6 F5 [, H/ Z- c
//COleVariant strVar("This is a test");. g/ {5 D% [3 H7 f
_variant_t strVar("This is a test");. u& N- d2 [5 v$ G( O' t
BSTR bstrText = strVar.bstrVal; . q: Y" q- J. {! b/ K
+ O7 x6 ]7 w1 v1 D  y" r, O
  方法三,使用_bstr_t,这是一种最简单的方法。例如:, G; m+ P$ v! K9 L) S

) J* U3 g6 F2 w4 X. h. [BSTR bstrText = _bstr_t("This is a test");
) v! {5 _% V+ i! W% l2 {
2 ]4 |5 X) k, O0 c% p  方法四,使用CComBSTR。例如:
4 f) A# m+ ]& S( K9 _. ]! ]+ h
& `. C9 l6 w  B: dBSTR bstrText = CComBSTR("This is a test"); 9 l8 N$ Q, f- T1 L9 P" K( U
! o! b9 `" |- M. h, ]8 D, d* o
  或) K0 u. G- o: r2 Y$ ~3 e

+ d5 s) j! d& Q) `" e3 _+ a" qCComBSTR bstr("This is a test");
- Q: \3 I  _! d& p: ^BSTR bstrText = bstr.m_str;
1 p; u4 _& E/ }+ R( T* C! V3 o0 h5 D$ ~7 H
  方法五,使用ConvertStringToBSTR。例如:
6 ?" G, _6 y6 m/ a* ^  M& I9 D/ {6 o, l; I
char* lpszText = "Test";) T2 O' N& |  p# L$ @# Y# x  l+ i' P
BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText); - K% K' x, o6 B9 i( m
: {! l5 e, r2 D0 y( B
  (5) CString转换成BSTR
/ P8 W: n( c4 W: k4 J+ c" Y) y
6 D* R7 J; w& T* K3 e- W$ K( k! n  通常是通过使用CStringT::AllocSysString来实现。例如:
4 h" f: Q* C% \6 @! Z* q
; @+ J" I% t5 d" v2 O; R. WCString str("This is a test");4 y8 l" G  q# z' s# Q! W$ a
BSTR bstrText = str.AllocSysString();
5 ]1 c2 ~8 H. t" ?( ~( a1 r
/ F# z5 H+ X/ @  k- O' U0 g+ jSysFreeString(bstrText); // 用完释放  - k* `+ O* Y) Y* B% d6 ?" r$ S  k, Y
- u6 N0 P: O2 R8 l" p
  (6) BSTR转换成CString
9 B$ @& S5 P# x, Y% r
: _  W) \3 ~; q# }4 O% E  一般可按下列方法进行:# X5 L$ b: L- I7 ~) O8 _& B
/ J8 G( ]; r  f) j& ^) p- y
BSTR bstrText = ::SysAllocString(L"Test");
- C) B) _1 n; p$ `% a8 XCStringA str;
9 J- ]: W9 c" ~; Z# G/ j, gstr.Empty();4 @6 I4 C, z; E0 B+ _9 b# G
str = bstrText;  ( C7 N. ~# g+ I/ h/ |

# V- S# l+ I$ S6 w& i  或
% ~' ]/ Y7 r+ \! x5 a" a! [/ ~  U% P! E! r* h
CStringA str(bstrText);
" R/ W7 |% j, F' {6 [# H6 l
. x- \/ [) ?( n% U( m  (7) ANSI、Unicode和宽字符之间的转换0 @- q4 X. L& `
8 Z& s" H0 x2 T- |: O: G
  方法一,使用MultiByteToWideChar将ANSI字符转换成Unicode字符,使用WideCharToMultiByte将Unicode字符转换成ANSI字符。
) D4 f* \8 a3 ?3 F
0 i5 Z& S4 E- ?0 w& P% F  方法二,使用“_T”将ANSI转换成“一般”类型字符串,使用“L”将ANSI转换成Unicode,而在托管C++环境中还可使用S将ANSI字符串转换成String*对象。例如:1 `2 K1 U& u: y5 i8 J% x6 a

/ l- Z5 J, P' F  k7 \TCHAR tstr[] = _T("this is a test");! K1 I% T: m( D; O0 s; \
wchar_t wszStr[] = L"This is a test";% |. K8 w4 ]" ]. W
String* str = S”This is a test”;   {: E4 U/ R+ l7 V6 h. V- u) U

0 n$ C; V2 E; N: }/ Z  方法三,使用ATL 7.0的转换宏和类。ATL7.0在原有3.0基础上完善和增加了许多字符串转换宏以及提供相应的类,它具有如图3所示的统一形式:5 V: T% S. R  _" l  B) T
# a* j0 K- O! j- M
  其中,第一个C表示“类”,以便于ATL 3.0宏相区别,第二个C表示常量,2表示“to”,EX表示要开辟一定大小的缓冲。SourceType和DestinationType可以是A、T、W和OLE,其含义分别是ANSI、Unicode、“一般”类型和OLE字符串。例如,CA2CT就是将ANSI转换成一般类型的字符串常量。下面是一些示例代码:
7 a6 K% _+ C. m, J: `8 P3 }1 ^# o' }1 [5 I7 |8 Q
LPTSTR tstr= CA2TEX<16>("this is a test");" Z; x5 W. b8 d. o" P
LPCTSTR tcstr= CA2CT("this is a test");
& m, _' ^6 n9 N6 V: xwchar_t wszStr[] = L"This is a test";' z9 [( `; Q) W0 V( Q& F
char* chstr = CW2A(wszStr);  / ]- g* X6 C! [, v# f' R

, }" U7 `, }# r5 {5 k  A) d- Z  六、结语0 W+ a7 o+ Z4 R- p3 p

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

本版积分规则

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

GMT+8, 2025-11-15 04:53 , Processed in 0.017462 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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