找回密码
 注册
查看: 4732|回复: 0

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

[复制链接]
发表于 2003-10-19 13:10:41 | 显示全部楼层 |阅读模式
2002-12-05· ·丁有和··yesky
! I) M" y9 ]5 N
4 ?; Q% W2 l/ K0 Z' |& W' R
( c. ?0 p/ E3 s6 Z+ E# x+ v  Visual C++.NET涉及到ATL/ATL Server、MFC和托管C++等多种编程方式,不仅功能强大而且应用广泛。在编程中,我们常常会遇到ANSI、Unicode以及BSTR不同编码类型的字符串转换操作。本文先介绍基本字符串类型,然后说明相关的类,如CComBSTR、_bstr_t、CStringT等,最后讨论它们的转换方法,其中还包括使用最新ATL7.0的转换类和宏,如CA2CT、CA2TEX等。
8 e, ]; T% A: Z
$ e# c* u# f5 O" e( A  一、BSTR、LPSTR和LPWSTR
7 b4 T( r# d) N& r6 K! T4 ?3 w  A: z! l7 U
  在Visual C++.NET的所有编程方式中,我们常常要用到这样的一些基本字符串类型,如BSTR、LPSTR和LPWSTR等。之所以出现类似上述的这些数据类型,是因为不同编程语言之间的数据交换以及对ANSI、Unicode和多字节字符集(MBCS)的支持。
; \& l. F* @1 h! e
3 i. k+ U/ O0 F  那么什么是BSTR、LPSTR以及LPWSTR呢?3 u3 m0 S) y+ C; P8 q- r
; W: p* |6 |( ?
  BSTR(Basic STRing,Basic字符串)是一个OLECHAR*类型的Unicode字符串。它被描述成一个与自动化相兼容的类型。由于操作系统提供相应的API函数(如SysAllocString)来管理它以及一些默认的调度代码,因此BSTR实际上就是一个COM字符串,但它却在自动化技术以外的多种场合下得到广泛使用。图1描述了BSTR的结构,其中DWORD值是字符串中实际所占用的字节数,且它的值是字符串中Unicode字符的两倍。8 Y/ t) L7 @) I# P9 l
; |% ^5 v- |  B4 u% `: F5 G
  LPSTR和LPWSTR是Win32和VC++所使用的一种字符串数据类型。LPSTR被定义成是一个指向以NULL(‘\0’)结尾的8位ANSI字符数组指针,而LPWSTR是一个指向以NULL结尾的16位双字节字符数组指针。在VC++中,还有类似的字符串类型,如LPTSTR、LPCTSTR等,它们的含义如图2所示。2 E& L$ q/ @. q

3 ?$ k( o3 k7 _( U  例如,LPCTSTR是指“long pointer to a constant generic string”,表示“一个指向一般字符串常量的长指针类型”,与C/C++的const char*相映射,而LPTSTR映射为 char*。
2 F  u0 s5 Y) }& ^( M5 A+ R6 F& I( y$ U2 i; P; Y/ C5 C  a
  一般地,还有下列类型定义:8 F5 w4 u3 v( m# q
- _. o# T5 o5 K2 u9 f. q6 o
#ifdef UNICODE 9 _6 I& G8 R% O
 typedef LPWSTR LPTSTR;3 {- \' z( f( I8 {9 m1 A
 typedef LPCWSTR LPCTSTR; * V) s) e' Q) C- z8 r
#else
/ D2 C- R. Y: ~# | typedef LPSTR LPTSTR;
' H& G, h- |) | typedef LPCSTR LPCTSTR;
7 B8 T9 }$ e* g- c5 G& A#endif  
* T' S' r$ S8 @( Q! S! x7 G
% F4 u. `0 o9 u  P9 W0 E% P+ Q" ^4 p  二、CString、CStringA 和 CStringW$ S2 x1 _" w/ F- G! Q/ Z" I/ ^

2 e, V! Y; |) G+ V( k4 f9 N5 s  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应用程序中经常用到,这里不再重复。# e0 x9 ?8 Q3 O! O
( Y# z' `9 f+ h- ~3 l
  三、VARIANT、COleVariant 和_variant_t
5 k% W7 u" a) c, S6 L
% E6 O! K( A' G+ i! f  在OLE、ActiveX和COM中,VARIANT数据类型提供了一种非常有效的机制,由于它既包含了数据本身,也包含了数据的类型,因而它可以实现各种不同的自动化数据的传输。下面让我们来看看OAIDL.H文件中VARIANT定义的一个简化版:( @2 w9 X8 k  f

6 }" a1 M1 t% E6 f8 R+ ]) m6 lstruct tagVARIANT {
3 {! H: S& a3 X5 |' ^3 i VARTYPE vt;
' S* h/ K6 z" j: A union {
- R- j: w4 s5 \  short iVal; // VT_I2.8 H& Z6 \  K8 L. l: ]4 t0 G
  long lVal; // VT_I4.! J% I! o6 o. v; W) B9 Y
  float fltVal; // VT_R4.
+ B* \0 {( i- F; g  double dblVal; // VT_R8.. E) @! E+ W6 w" G
  DATE date; // VT_DATE.
/ e  d- u6 I3 n  BSTR bstrVal; // VT_BSTR.
% A- v6 ]( P1 P0 l! l$ |2 u7 T  …
6 g. k9 g* h  z4 j2 [  short * piVal; // VT_BYREF|VT_I2.
! `0 v& E+ K$ ^; _6 J& L$ N  long * plVal; // VT_BYREF|VT_I4.
9 c# ~  m& L: W# W3 m7 h& V& ^1 i" `  float * pfltVal; // VT_BYREF|VT_R4.
7 G: g2 w, F7 s* @5 [( \  double * pdblVal; // VT_BYREF|VT_R8.! G/ K% \( [( S; Y
  DATE * pdate; // VT_BYREF|VT_DATE.
9 y  w3 G# u0 G7 u4 Y  BSTR * pbstrVal; // VT_BYREF|VT_BSTR.
. h5 k% E+ ~9 f0 w };' t3 T: G* z: E1 S9 U9 h
}; 5 H# `. t$ s$ M0 H% b8 J
, L2 Z; ~/ T  q/ S4 Y
  显然,VARIANT类型是一个C结构,它包含了一个类型成员vt、一些保留字节以及一个大的union类型。例如,如果vt为VT_I2,那么我们可以从iVal中读出VARIANT的值。同样,当给一个VARIANT变量赋值时,也要先指明其类型。例如:
) _( o2 j4 N' n' _  s7 h0 X7 U
. c  G9 X/ `# u: D' vVARIANT va;" F# c: p" Z6 T; C5 H. l+ p
:: VariantInit(&va); // 初始化
1 H* \! ?! M! f5 aint a = 2002;9 O! x! u4 b' _
va.vt = VT_I4; // 指明long数据类型% W7 T) p; q/ j, V9 q! |; f, I
va.lVal = a; // 赋值 ! y6 u9 p* p* g. H) w' ?* \
, Y/ b2 ]8 r4 [6 h& I
  为了方便处理VARIANT类型的变量,Windows还提供了这样一些非常有用的函数:( `# M( W7 \% p0 s- d; v' D& V- q$ Z
, }, Y! O' d, w0 \" L
  VariantInit —— 将变量初始化为VT_EMPTY;
# t( t; J( F  M! ^" x* ]# k; P
, e4 _$ P# r# U' J. o  VariantClear —— 消除并初始化VARIANT;  g" Y% B8 M/ `) W, O$ A  m; p

/ I  J* V6 h4 Y+ r* U- p  VariantChangeType —— 改变VARIANT的类型;$ w4 o& h# D( P9 i% H

) [6 J$ z2 I8 V* l7 i  VariantCopy —— 释放与目标VARIANT相连的内存并复制源VARIANT。
7 F: \- K; Q6 @- z& x+ d* q$ _6 G+ A$ O6 m( b6 O2 B2 l
  COleVariant类是对VARIANT结构的封装。它的构造函数具有极为强大大的功能,当对象构造时首先调用VariantInit进行初始化,然后根据参数中的标准类型调用相应的构造函数,并使用VariantCopy进行转换赋值操作,当VARIANT对象不在有效范围时,它的析构函数就会被自动调用,由于析构函数调用了VariantClear,因而相应的内存就会被自动清除。除此之外,COleVariant的赋值操作符在与VARIANT类型转换中为我们提供极大的方便。例如下面的代码:
' C6 M8 t. F/ W! C" b  O7 ^* s5 S+ t& G2 s! Q7 W8 y; Z; p
COleVariant v1("This is a test"); // 直接构造
2 B6 R, s: {. N- `* h1 L: Y! \COleVariant v2 = "This is a test"; ; T: @2 o& b9 l  V( d% B& W
// 结果是VT_BSTR类型,值为"This is a test"6 ]; Z! p8 T: E' w
COleVariant v3((long)2002);
* G' ^% `" Y$ ^- eCOleVariant v4 = (long)2002;
4 x7 \! B5 V8 E+ ?7 T// 结果是VT_I4类型,值为2002
* _/ y2 O6 g& Y  I$ e% B, ^3 c  A& O
  _variant_t是一个用于COM的VARIANT类,它的功能与COleVariant相似。不过在Visual C++.NET的MFC应用程序中使用时需要在代码文件前面添加下列两句:
; g0 t; ^7 t) t6 ^6 Q' ^$ h
. l0 B) N5 f. n; R. F7 c; }  #include "comutil.h"
1 J% X# L" }& a8 T5 F* s$ N. t- F
6 G2 f% V$ F) _4 x2 v  #pragma comment( lib, "comsupp.lib" )
; N4 W$ ^& j9 H. `8 i3 q
' j6 v) a9 B  \1 v+ G0 i1 N. X  四、CComBSTR和_bstr_t4 a: X! L3 w& [) e  V. S6 j
6 o1 q8 t5 E5 k; G+ ^; G
  CComBSTR是对BSTR数据类型封装的一个ATL类,它的操作比较方便。例如:
- g$ `, Z: H3 K1 j9 v9 y, q  n% q% y2 l8 q. K/ v( c/ z/ w
CComBSTR bstr1;   b8 ]# F- U- S) b1 f# S
bstr1 = "Bye"; // 直接赋值: F8 L( Q- K( A( v1 |
OLECHAR* str = OLESTR("ta ta"); // 长度为5的宽字符' O& f: G' ]2 o( D" Z
CComBSTR bstr2(wcslen(str)); // 定义长度为5& m, [: X$ l4 k: r4 t2 T0 C) x+ p1 C
wcscpy(bstr2.m_str, str); // 将宽字符串复制到BSTR中
3 \0 S/ [# t( l+ l( VCComBSTR bstr3(5, OLESTR("Hello World"));
" h2 V: v6 r# z4 E! N, g4 v7 _CComBSTR bstr4(5, "Hello World");
2 b+ ?; r' ]2 |CComBSTR bstr5(OLESTR("Hey there")); & R1 T) [2 h& o7 p
CComBSTR bstr6("Hey there"); / P  a% H- C& h- [( _9 g9 c( L
CComBSTR bstr7(bstr6); & C4 W6 W9 {( H" Y2 c( j
// 构造时复制,内容为"Hey there"
4 L! f8 J: x+ X* Z, J3 ?0 Y' ?
4 y( @; ?, `* r0 }) W0 ~  _bstr_t是是C++对BSTR的封装,它的构造和析构函数分别调用SysAllocString和SysFreeString函数,其他操作是借用BSTR API函数。与_variant_t相似,使用时也要添加comutil.h和comsupp.lib。
) q0 Z% K, O* g# p+ z; q3 }0 a0 L. g* H" g# _2 K* [
  五、BSTR、char*和CString转换
* Y. R: I: s( U6 L! l
* l3 V! W/ L$ I* ]7 g1 v  (1) char*转换成CString
/ {! O' l. U# {8 y% a$ `; @7 q0 l8 M( \3 X0 ^& ?  b
  若将char*转换成CString,除了直接赋值外,还可使用CString::Format进行。例如:7 w7 E. l2 R. U$ R+ t" i" G
# J  L+ W0 D- C- ^
char chArray[] = "This is a test";) F" `+ C& d' q# M
char * p = "This is a test"; . r# L1 m/ v5 o! X2 W4 J
$ k  o0 [3 u. R0 `
  或) E# s* \* T4 k" |( z9 {

+ {0 s/ P5 Q% e0 v8 y2 _0 A- uLPSTR p = "This is a test"; 6 V3 T3 @7 N& s; {- t' ~# [; ?9 w

/ Y6 b3 z5 x0 k3 P: u3 g: n  或在已定义Unicode应的用程序中
7 v) |) j0 X* ?; {% v5 i8 M) X# T  t, z7 q  ?7 q: |
TCHAR * p = _T("This is a test"); 4 n+ w( j' t' Y+ V6 v& [

6 b; `/ \5 \$ O+ |8 `( h  或7 L* M3 L1 \2 a* S( Y4 p" f9 @2 p1 z

+ V  r1 ^% t! P- n: L' |LPTSTR p = _T("This is a test");' t+ i7 N3 s" M# R& r/ }* F7 r# @% @
CString theString = chArray;
$ w* k% b; N) L+ m- N8 ptheString.Format(_T("%s"), chArray);. R: P; \3 l: u. |! O3 L
theString = p; ) `! B2 ~) }  Z9 H: @

2 A, F+ z0 [2 |9 `7 B! _4 D  (2) CString转换成char*
+ q8 P# R: [% Z2 z+ P% V
' s; i6 x; _/ I) B$ c+ b4 K  若将CString类转换成char*(LPSTR)类型,常常使用下列三种方法:
6 W& x8 s+ g4 B. |6 L
( D: e# M) P; x  方法一,使用强制转换。例如:
! j0 I" y+ O7 ^$ Z2 F7 _5 ~3 t+ q( ]7 Q
CString theString( "This is a test" );
0 \" B& h) A8 _2 N2 }. {- h! mLPTSTR lpsz =(LPTSTR)(LPCTSTR)theString;  
- k, M9 E- |9 `$ u: t; _3 j+ ]6 Y, D# i$ Q% x
  方法二,使用strcpy。例如:
" H* b3 @8 L$ f& p$ k; `
5 Y' ]& k/ F, U) KCString theString( "This is a test" );7 Q- J6 J( k( [6 i5 T8 l) P' U; a
LPTSTR lpsz = new TCHAR[theString.GetLength()+1];
( i2 {* e) }9 e; v$ i" w_tcscpy(lpsz, theString); * o. \& Q* I1 L/ c% E
0 R2 |4 a$ J9 }* o5 e( a
  需要说明的是,strcpy(或可移值Unicode/MBCS的_tcscpy)的第二个参数是 const wchar_t* (Unicode)或const char* (ANSI),系统编译器将会自动对其进行转换。5 \+ R/ A! _1 T' y4 @, ]
' D8 N0 |% m+ q! L, I: l
  方法三,使用CString::GetBuffer。例如:6 b. A% B2 l- m6 v  I

" p* ^0 N6 @& R* W: T! gCString s(_T("This is a test "));
! j* ?" {& G, K* ^' G# ILPTSTR p = s.GetBuffer();- {& C6 Z5 e# O" A
// 在这里添加使用p的代码  x% y1 Q3 P, \
if(p != NULL) *p = _T('\0');# F$ P1 r* Y* Y
s.ReleaseBuffer(); 2 ]" y9 p* B6 f# D4 n/ n# G/ K; M8 q
// 使用完后及时释放,以便能使用其它的CString成员函数 / i" _, k( m  q+ |' d
5 a4 N2 G& B" O
  (3) BSTR转换成char*
: {) o6 N4 Z! r6 D) ^7 L' |+ o5 i+ V5 i- A
  方法一,使用ConvertBSTRToString。例如:# m& A5 b9 v6 A2 u* ]
1 q+ b- d9 X3 \0 `9 c
#include
& s- L$ P; o# J4 x#pragma comment(lib, "comsupp.lib")
0 B& V3 K; e$ _int _tmain(int argc, _TCHAR* argv[]){
1 ?' G2 T2 e+ M" t0 H$ U* B. yBSTR bstrText = ::SysAllocString(L"Test");
0 h% B* a2 C% A& Ychar* lpszText2 = _com_util::ConvertBSTRToString(bstrText);
! b% m) H) W8 p9 x( C% D  YSysFreeString(bstrText); // 用完释放
: S1 |$ Y# B5 _. q% T- k: Vdelete[] lpszText2;
9 S; G6 ^  Y, Z' _. V; b- breturn 0;; m0 m( X8 w" Z' e4 P
}  0 M7 H  v( e! ^& G9 Z
; G2 W1 G0 C9 A& Z
  方法二,使用_bstr_t的赋值运算符重载。例如:# u9 n! Z0 J% C
1 K  ?$ C9 @& Q+ A1 V  f5 R
_bstr_t b = bstrText;
# D) p( q* p. ]' v8 Y, t" Hchar* lpszText2 = b;
" {6 w8 C# U1 |) F9 Y, X- v2 ~' L9 t) D+ F3 w  c% b
  (4) char*转换成BSTR9 u2 Q0 c/ a8 I' M+ H1 c- c

; K: j# U) U# Z+ @+ B6 H  方法一,使用SysAllocString等API函数。例如:
" T. V  i' f7 v3 z, s7 K6 f8 H1 `6 k+ B* A0 L- _
BSTR bstrText = ::SysAllocString(L"Test");# N. Y3 l7 Q9 v5 [2 s' _! |! X7 U
BSTR bstrText = ::SysAllocStringLen(L"Test",4);
1 u+ J0 T4 F; Z4 m1 P* \BSTR bstrText = ::SysAllocStringByteLen("Test",4);
  ]9 {. I. \( S# Z
: J5 U; E  x2 I  d/ q- k8 c! V  方法二,使用COleVariant或_variant_t。例如:
3 K: M3 }/ [( y, }6 Q: O! J2 B" J( ]2 r/ l% m" E, M
//COleVariant strVar("This is a test");/ {' g) y0 @0 M5 [1 {
_variant_t strVar("This is a test");6 [. m% p2 s+ ~5 K" W8 A: P2 ^
BSTR bstrText = strVar.bstrVal; : b; p# }1 C6 x' S7 n& A

1 F+ k, m7 c1 B  `$ ?  方法三,使用_bstr_t,这是一种最简单的方法。例如:
0 B+ ^) I" j# G+ L& k1 V- ~5 U: T6 L, {1 o( V6 ?. ~6 P
BSTR bstrText = _bstr_t("This is a test"); ' v. F  e# C- C7 K% R: |

( h& `. e. X& p8 a( T  方法四,使用CComBSTR。例如:
3 F6 B6 _- f. _0 ^( Y9 Z2 x' |* q9 G- [6 ~6 f+ N3 E; `) j
BSTR bstrText = CComBSTR("This is a test"); / `  _, @: p+ w8 c: z+ G. o; C

% W: I" [1 J2 m; f) p  或9 T" K3 G' y$ A2 \1 u) G
, ~3 C9 h; r' R; k! Y. O* i
CComBSTR bstr("This is a test");8 H( ]$ G$ I2 R/ F9 n6 A
BSTR bstrText = bstr.m_str; ( c7 b$ z- h! z  c9 h! Y4 l2 k& M

/ y! |- M3 \1 E7 x5 X  方法五,使用ConvertStringToBSTR。例如:
' _5 `3 b3 A- ]3 m7 g- I: q% r3 A: L1 C4 M) |
char* lpszText = "Test";& W7 V% a2 b/ ^
BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText);
) q% ~: z+ U. Q4 ~+ H- H
! M& x5 d/ M. k7 A  (5) CString转换成BSTR
' X" |2 T2 m) [7 M  @* I0 }" O3 k2 X9 W0 S0 a. U0 g
  通常是通过使用CStringT::AllocSysString来实现。例如:
8 c9 d/ M6 H1 Z* {1 H3 Z% l
% @$ N3 v& `3 D- m+ x8 e' l1 _* QCString str("This is a test");
5 r( ^2 W5 v! S5 m1 t% d+ ?BSTR bstrText = str.AllocSysString();
; _* Z8 _# j( t4 P…" y2 Z9 W( h! c
SysFreeString(bstrText); // 用完释放  
1 f1 Y2 l6 @$ W) F, G# L1 h; G' {4 {" Y6 p- b9 M
  (6) BSTR转换成CString
$ J6 R3 w$ m/ Z7 Y
& \0 z, L; E7 z& ^  一般可按下列方法进行:5 Z3 A2 j( u! Y2 x4 @1 [
0 f% r4 D! L' `4 B$ k
BSTR bstrText = ::SysAllocString(L"Test");
& e3 X1 w  b: e) _1 zCStringA str;; R) k5 W( s$ w9 o! B! Q2 `/ w* `
str.Empty();
: s% U/ g2 n3 ]/ i. Pstr = bstrText;  ) |3 H& [3 `7 P1 W% s
% ]+ j/ X. C! T4 v
  或
/ ^" k; P6 p$ P4 j' n4 F% P0 d: W/ H& [' W# O* ^8 {
CStringA str(bstrText);
' F+ x, \3 `; _7 t, g# A/ W* X  ]6 }0 O
  (7) ANSI、Unicode和宽字符之间的转换  {- Y1 \' }; b0 _* \9 q# t) ^9 g
( g' Q/ m5 L1 O! {
  方法一,使用MultiByteToWideChar将ANSI字符转换成Unicode字符,使用WideCharToMultiByte将Unicode字符转换成ANSI字符。
9 A* s) N' x1 A% _
1 ~* B. g; j4 F' G+ T  方法二,使用“_T”将ANSI转换成“一般”类型字符串,使用“L”将ANSI转换成Unicode,而在托管C++环境中还可使用S将ANSI字符串转换成String*对象。例如:
2 O2 e. t1 w5 g* U0 ~$ M. R
: R# w, V) z* B$ r' mTCHAR tstr[] = _T("this is a test");4 t$ S4 D: {) W1 W, W, e
wchar_t wszStr[] = L"This is a test";
& g# v) L4 u! ?1 WString* str = S”This is a test”;
- N3 w! M3 ~: E$ f" {& x
. I$ K+ x$ l- f" y# Q) Z  方法三,使用ATL 7.0的转换宏和类。ATL7.0在原有3.0基础上完善和增加了许多字符串转换宏以及提供相应的类,它具有如图3所示的统一形式:% a7 F+ ?: z0 d5 J( M* ~. K- A
9 C. J( P6 F, Y. @6 y4 P
  其中,第一个C表示“类”,以便于ATL 3.0宏相区别,第二个C表示常量,2表示“to”,EX表示要开辟一定大小的缓冲。SourceType和DestinationType可以是A、T、W和OLE,其含义分别是ANSI、Unicode、“一般”类型和OLE字符串。例如,CA2CT就是将ANSI转换成一般类型的字符串常量。下面是一些示例代码:7 h/ P9 H. U$ }" b4 @* M/ b
9 \- m" ?( P$ N3 l' b! p
LPTSTR tstr= CA2TEX<16>("this is a test");" y2 m" ?# t# n* G$ h7 b2 l# G
LPCTSTR tcstr= CA2CT("this is a test");7 x& y$ T. f; ]* Y& _# H8 T
wchar_t wszStr[] = L"This is a test";% z8 B" R9 S- g0 f/ f$ V
char* chstr = CW2A(wszStr);  
- H' w0 v9 q& I7 ]9 r
9 G0 n* C/ p6 p: x# e: v$ h' X  六、结语
, ^+ U8 G3 M+ d, T" P! @: |6 ~" I* C, Z' N: I" i
  几乎所有的程序都要用到字符串,而Visual C++.NET由于功能强大、应用广泛,因而字符串之间的转换更为频繁。本文几乎涉及到目前的所有转换方法。当然对于.NET框架来说,还可使用Convert和Text类进行不同数据类型以及字符编码之间的相互转换。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2026-10-2 00:20 , Processed in 0.018175 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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