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

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

[复制链接]
发表于 2003-10-19 13:10:41 | 显示全部楼层 |阅读模式
2002-12-05· ·丁有和··yesky
; L) D7 M, {, ]4 j! e
9 s8 S3 ]9 g/ S5 ]" h1 A% \$ x2 m0 k2 j9 O- s8 X4 T
  Visual C++.NET涉及到ATL/ATL Server、MFC和托管C++等多种编程方式,不仅功能强大而且应用广泛。在编程中,我们常常会遇到ANSI、Unicode以及BSTR不同编码类型的字符串转换操作。本文先介绍基本字符串类型,然后说明相关的类,如CComBSTR、_bstr_t、CStringT等,最后讨论它们的转换方法,其中还包括使用最新ATL7.0的转换类和宏,如CA2CT、CA2TEX等。6 j+ ~3 I# W  c: ~8 }! Q

9 C' ~  g8 ~8 C  O  一、BSTR、LPSTR和LPWSTR# H: B/ ^& \0 y' U" g/ u
2 B8 G. I5 _8 z9 t
  在Visual C++.NET的所有编程方式中,我们常常要用到这样的一些基本字符串类型,如BSTR、LPSTR和LPWSTR等。之所以出现类似上述的这些数据类型,是因为不同编程语言之间的数据交换以及对ANSI、Unicode和多字节字符集(MBCS)的支持。3 a6 V" |! z" o$ g8 d4 C- Y

: I+ W  y! ]" m' ?; M8 k) s* m  那么什么是BSTR、LPSTR以及LPWSTR呢?6 I. ^9 U& m' o+ m

0 G( N. ?  i3 \! c$ q  BSTR(Basic STRing,Basic字符串)是一个OLECHAR*类型的Unicode字符串。它被描述成一个与自动化相兼容的类型。由于操作系统提供相应的API函数(如SysAllocString)来管理它以及一些默认的调度代码,因此BSTR实际上就是一个COM字符串,但它却在自动化技术以外的多种场合下得到广泛使用。图1描述了BSTR的结构,其中DWORD值是字符串中实际所占用的字节数,且它的值是字符串中Unicode字符的两倍。
/ s# ]& S$ e7 p8 w& k0 w
8 T1 m/ g+ z+ }/ ]% W9 U; B  LPSTR和LPWSTR是Win32和VC++所使用的一种字符串数据类型。LPSTR被定义成是一个指向以NULL(‘\0’)结尾的8位ANSI字符数组指针,而LPWSTR是一个指向以NULL结尾的16位双字节字符数组指针。在VC++中,还有类似的字符串类型,如LPTSTR、LPCTSTR等,它们的含义如图2所示。
# m8 ~* b4 s+ `. Y1 _. x  g; Q
% U5 y: r/ p9 W# ?  例如,LPCTSTR是指“long pointer to a constant generic string”,表示“一个指向一般字符串常量的长指针类型”,与C/C++的const char*相映射,而LPTSTR映射为 char*。
/ H  w: ^, ^" V3 b7 ^, z( @3 Q# B, U. y  r' I- t* E8 ^1 ?1 x
  一般地,还有下列类型定义:
$ u0 `: g; N/ {6 x8 K. |
3 x8 S0 z! Q/ M$ q1 K% L#ifdef UNICODE * p/ r" L. k/ g* `" u) Z# I
 typedef LPWSTR LPTSTR;
* G5 @4 @6 F4 w! a0 h) e typedef LPCWSTR LPCTSTR;
, v( _. x5 w+ u/ _5 c5 j6 o8 t#else
/ O1 R) d& Z5 w typedef LPSTR LPTSTR;
. C, r. Z# q- T1 K' y# `/ m9 h0 F typedef LPCSTR LPCTSTR; - j' l% W3 ]2 g( b$ [% ~
#endif  
4 w9 v3 f1 G$ {7 ~: x9 ?8 i# e9 C/ d7 m( G
  二、CString、CStringA 和 CStringW% _8 r0 Y1 N( E& v) }& i
, P! C$ V; s+ L5 r. V& m5 ?
  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 [, y2 o6 K* P: a1 ~4 l
6 K  _% q$ d2 X2 O/ O+ A- g; L: D
  三、VARIANT、COleVariant 和_variant_t9 X% m2 C- g2 e

% [' K7 C" R: s! W& ~4 B% W  j0 @  在OLE、ActiveX和COM中,VARIANT数据类型提供了一种非常有效的机制,由于它既包含了数据本身,也包含了数据的类型,因而它可以实现各种不同的自动化数据的传输。下面让我们来看看OAIDL.H文件中VARIANT定义的一个简化版:
  _. k; r: x( ]8 n7 O! c/ W) J' C2 r  h$ s. j5 `1 v; n) a3 ?% Z; E
struct tagVARIANT {
2 J8 o7 [7 ?. Z VARTYPE vt;
, }- H2 r0 U8 Z/ J# D3 B/ l union {8 i3 k$ m# ~: v2 D5 ^% k
  short iVal; // VT_I2.% ^* d2 `8 I& |* ~. Y2 \
  long lVal; // VT_I4.. p  y" H7 c! _* x
  float fltVal; // VT_R4.
, ~, P  k1 n- |7 B4 K8 u  double dblVal; // VT_R8.8 A( k$ _0 @1 j( ]  W; ]
  DATE date; // VT_DATE.
$ ~/ o% ?+ ^* N  BSTR bstrVal; // VT_BSTR.
, k) R# ~: P/ Y* q: X  …) [2 _; K, Z2 t$ b, P/ y$ Y; U
  short * piVal; // VT_BYREF|VT_I2.
7 o( {) T# X5 z% _: z/ y  long * plVal; // VT_BYREF|VT_I4.
: U: m- c/ U& j' G  float * pfltVal; // VT_BYREF|VT_R4.
+ j* l  b6 @( d- H& `" ^  double * pdblVal; // VT_BYREF|VT_R8./ O. Z, C, E' }* Q& o& P4 R0 I2 @
  DATE * pdate; // VT_BYREF|VT_DATE.5 f( A4 [  C2 r. Z! X
  BSTR * pbstrVal; // VT_BYREF|VT_BSTR.( _* V! }4 d. y* l& V
 };6 R3 E8 K1 A% |& Z! K6 q* h1 w
}; + p) U- n/ B; ?  s7 t
2 Q. J" [$ m, r  n& ~
  显然,VARIANT类型是一个C结构,它包含了一个类型成员vt、一些保留字节以及一个大的union类型。例如,如果vt为VT_I2,那么我们可以从iVal中读出VARIANT的值。同样,当给一个VARIANT变量赋值时,也要先指明其类型。例如:
2 k  S6 p, X% j
& L, d* Q8 |" F0 bVARIANT va;9 p. h8 e1 J6 b7 s* u5 J  l7 U$ z
:: VariantInit(&va); // 初始化$ d( Q" L, u6 ~6 j- W
int a = 2002;
- E: p4 T" V7 d( Iva.vt = VT_I4; // 指明long数据类型
& s+ a  S1 ~4 Y' z- C5 }* S& C: cva.lVal = a; // 赋值 0 n1 l  B: Y  d
1 w1 _6 o2 ], e' T2 G
  为了方便处理VARIANT类型的变量,Windows还提供了这样一些非常有用的函数:1 r% Z* g7 y1 v

+ [9 F+ H) j  `$ V0 b/ V: q* A  VariantInit —— 将变量初始化为VT_EMPTY;
* S. i- R9 {% y1 j- c' [0 I$ ], \5 f% g0 J
  VariantClear —— 消除并初始化VARIANT;
3 w6 k" ?$ M9 }# \$ [' l: m) ^7 q& z" G% @  _4 L1 O
  VariantChangeType —— 改变VARIANT的类型;4 F7 Y' l! j' v
5 n( z* U. y- u$ w
  VariantCopy —— 释放与目标VARIANT相连的内存并复制源VARIANT。/ ?" z  D8 ^' p# J# b( b$ D
6 M0 b* m! p9 K- L& }1 N; r# E
  COleVariant类是对VARIANT结构的封装。它的构造函数具有极为强大大的功能,当对象构造时首先调用VariantInit进行初始化,然后根据参数中的标准类型调用相应的构造函数,并使用VariantCopy进行转换赋值操作,当VARIANT对象不在有效范围时,它的析构函数就会被自动调用,由于析构函数调用了VariantClear,因而相应的内存就会被自动清除。除此之外,COleVariant的赋值操作符在与VARIANT类型转换中为我们提供极大的方便。例如下面的代码:# @$ `0 U! \, {- s: @- ~& y

  J' j/ O; I' pCOleVariant v1("This is a test"); // 直接构造
1 B- S$ @3 P' _  BCOleVariant v2 = "This is a test"; ) I* l* U( k8 [+ v. S$ @
// 结果是VT_BSTR类型,值为"This is a test"# h7 I6 @/ t' Z
COleVariant v3((long)2002);
# s4 c( d6 V" I6 g9 d9 ^5 N: hCOleVariant v4 = (long)2002;: n1 v2 Q' Z0 [" L
// 结果是VT_I4类型,值为2002
( y1 d: f) q9 t+ g. z
0 ]( N9 c0 l) c- c5 |1 u/ ~  _variant_t是一个用于COM的VARIANT类,它的功能与COleVariant相似。不过在Visual C++.NET的MFC应用程序中使用时需要在代码文件前面添加下列两句:. b' v' I& i+ c% g4 s

! [) M* g  f: h1 ?$ J  #include "comutil.h"7 H1 s- P5 k( A5 i) _- m. _) B
+ G% O$ R8 d+ M; U$ s8 ^6 _# U
  #pragma comment( lib, "comsupp.lib" )
4 k9 }% |- i0 w% \, y$ L7 M3 H2 z. L9 V6 s; H
  四、CComBSTR和_bstr_t
/ X3 Z# z: |) S: S- l+ h$ h" F3 m: r( ^$ P# `
  CComBSTR是对BSTR数据类型封装的一个ATL类,它的操作比较方便。例如:# K+ U' g: W/ d3 D& _- O

" ]) ~$ D- h/ \# |. c: e( YCComBSTR bstr1; ; \! i4 L& _! U& s7 Z
bstr1 = "Bye"; // 直接赋值
# d/ c1 H1 s. N3 r. ^OLECHAR* str = OLESTR("ta ta"); // 长度为5的宽字符; \! d7 S/ ^7 ]* L% v6 n" J6 W: B
CComBSTR bstr2(wcslen(str)); // 定义长度为5
' l- _9 L' A2 ?8 Swcscpy(bstr2.m_str, str); // 将宽字符串复制到BSTR中
* g' i8 e5 S# K* n; q) B! ACComBSTR bstr3(5, OLESTR("Hello World"));
% ]1 M) B% m( q8 Q' LCComBSTR bstr4(5, "Hello World"); 4 l( P- ~/ z+ M' U$ {1 m
CComBSTR bstr5(OLESTR("Hey there"));
1 H, g$ ~0 a& Q  Z" I' ZCComBSTR bstr6("Hey there");
4 H% a1 P3 y% eCComBSTR bstr7(bstr6); . a& l. x0 x" v1 W& K
// 构造时复制,内容为"Hey there"
* O/ D. Z! Q" }  X2 e& s; s4 _* ^2 |" K/ S( C( c
  _bstr_t是是C++对BSTR的封装,它的构造和析构函数分别调用SysAllocString和SysFreeString函数,其他操作是借用BSTR API函数。与_variant_t相似,使用时也要添加comutil.h和comsupp.lib。) f/ K, J& \+ F7 D

* |# t6 J$ k2 i7 p4 G. w& p" L  五、BSTR、char*和CString转换7 Y1 F2 J7 ^) T# ]

' g9 y9 u; |0 T  (1) char*转换成CString
% S6 v; ]% s: h8 i5 |
5 Q4 a& @% ~8 f$ v1 W  若将char*转换成CString,除了直接赋值外,还可使用CString::Format进行。例如:
* W# A1 x# q# g3 W; `1 \7 Q! G/ d. X( I
char chArray[] = "This is a test";
9 B8 ^9 l+ h3 ?$ N: Wchar * p = "This is a test";
; x" J$ }% d" q% K0 Y6 B2 s& }: B5 z4 R" M: I3 K
  或0 J+ D" F1 S  f4 ~8 b4 c
  M1 D% l3 R$ y# C6 u7 R9 F" }
LPSTR p = "This is a test"; 4 V! {; n' _8 @  n  G- h9 A$ _

# j7 y; P2 e3 \2 T5 i6 h8 k' F  或在已定义Unicode应的用程序中
0 K8 V1 M4 {1 J$ N' v8 i
& `" f& X4 z! o3 _0 Q- K5 ITCHAR * p = _T("This is a test"); 6 Q3 _3 T( P% ~. O$ p3 F0 u
. V  v: }/ A: H5 w8 |% e
  或* r- `$ j! X/ y5 J4 I
: T% N8 o" q" R7 A1 u
LPTSTR p = _T("This is a test");
$ }/ Y3 g8 m4 [CString theString = chArray;
1 I" _* q% z+ N* OtheString.Format(_T("%s"), chArray);9 k/ ]9 _5 j1 G* ^+ ?
theString = p;
" V1 N% B) `! @2 l
+ C, v/ X  y) T! Y7 N$ ~) b  (2) CString转换成char*, L& S9 G/ ^# D+ w2 O7 U/ Y
# B/ L( f, j, e0 t
  若将CString类转换成char*(LPSTR)类型,常常使用下列三种方法:1 ^7 t/ r) u/ L7 Y
# u, g. ~3 Z+ F
  方法一,使用强制转换。例如:% ]5 A+ g. |. O  t! @
, f- ?) E+ F/ `* d- q
CString theString( "This is a test" );1 [! G. t4 @& w) J' @' V
LPTSTR lpsz =(LPTSTR)(LPCTSTR)theString;  * K3 _! C3 Z5 \+ D0 R+ V

: s7 W% I( I* f; ~* L4 p  方法二,使用strcpy。例如:
2 z$ W1 q, o: h6 E% L1 D' q9 B
CString theString( "This is a test" );
. }0 t7 s. Y: c. ^# g6 dLPTSTR lpsz = new TCHAR[theString.GetLength()+1];2 E( x3 f2 `9 \3 ]( X8 _
_tcscpy(lpsz, theString);
: ]( R+ B0 i' Z" g& N, l( L, ~- U/ i+ Q
  需要说明的是,strcpy(或可移值Unicode/MBCS的_tcscpy)的第二个参数是 const wchar_t* (Unicode)或const char* (ANSI),系统编译器将会自动对其进行转换。8 M0 v5 A: U1 M! ]
6 G& E& _: }' V; A5 [6 q2 }5 D8 f
  方法三,使用CString::GetBuffer。例如:+ v( L& p! W8 J7 S1 b2 f8 Y
$ V$ l( B  C. e; k1 b4 \- K
CString s(_T("This is a test "));4 y7 p& s! V3 C' `5 B- ]4 F. e' E
LPTSTR p = s.GetBuffer();) H+ O) x& b. e4 l9 E( F9 H
// 在这里添加使用p的代码
* k/ k) i( c. C* O* B6 ?3 y/ `/ xif(p != NULL) *p = _T('\0');  Y& q; c6 Q4 R) ]" ^- o, ~
s.ReleaseBuffer(); + D: F( [/ L2 |9 @& h
// 使用完后及时释放,以便能使用其它的CString成员函数
& f  k5 ^7 s3 K! }" r" i' l
8 ?5 y7 k9 A* f) U3 z1 w* {  (3) BSTR转换成char*
( Q" \) ]: G5 x7 H
+ K4 |6 _+ y$ L4 k& p. @  方法一,使用ConvertBSTRToString。例如:. u- t/ K" O' u+ d' q$ q
% V( `, D2 c+ u5 r
#include
2 ^. v1 i5 N8 C#pragma comment(lib, "comsupp.lib"), _7 M5 L- [4 Q: Q5 Q
int _tmain(int argc, _TCHAR* argv[]){
, K* ?& h' `3 ^5 k$ Z: EBSTR bstrText = ::SysAllocString(L"Test");3 x* ~" @0 {: [# K$ k# v9 `+ h
char* lpszText2 = _com_util::ConvertBSTRToString(bstrText);
2 R- m0 S: H2 _% s3 ?  T" gSysFreeString(bstrText); // 用完释放
' |9 [0 @. a* W; e/ q9 M, P: T) l, ]delete[] lpszText2;! f/ m+ ?  |9 J+ f) b& g
return 0;! {8 y) y3 H1 s, }: r0 V+ ]/ t
}  
9 g) `) C, g6 W" W7 h' k
$ A- s4 y% m4 _: y5 s2 `9 D  方法二,使用_bstr_t的赋值运算符重载。例如:
+ V+ T. w- q8 H. x. M1 H0 v+ s" {- g; y5 \; w/ ~
_bstr_t b = bstrText;
0 w+ q9 n1 U; L5 w$ P4 C7 Tchar* lpszText2 = b; 2 \& t, a3 E) F/ u- y; }% f5 a
0 P# l% P4 N  U' e6 @0 X7 Q
  (4) char*转换成BSTR
% W: I# L2 Y$ l8 d) o! j0 h, h; @' S5 h6 d: W% g
  方法一,使用SysAllocString等API函数。例如:' t5 E( t  `1 S1 ?! m
5 ^- v1 d6 @) [' w. O& v
BSTR bstrText = ::SysAllocString(L"Test");
4 i7 h* Z: I" p8 ~BSTR bstrText = ::SysAllocStringLen(L"Test",4);
; j7 j8 `) c7 s# v2 _$ _# mBSTR bstrText = ::SysAllocStringByteLen("Test",4); ; D% Q: U8 g8 [+ Z- N1 Q* F

. O% g3 ]( ]' V& g8 _5 V) W3 p  方法二,使用COleVariant或_variant_t。例如:' ^5 {2 F* e. i3 e
- j9 j7 b- {6 b2 i  V* k
//COleVariant strVar("This is a test");
* u2 Y+ A. i& a' [_variant_t strVar("This is a test");
" b8 w+ I5 B' vBSTR bstrText = strVar.bstrVal; # p( ]+ B9 S' {2 i. n, g) s
, s6 D! W  y. F$ u' d: a$ `
  方法三,使用_bstr_t,这是一种最简单的方法。例如:2 E2 F: h  c" P7 S- a% E
) R: t1 _5 d4 d8 s) k
BSTR bstrText = _bstr_t("This is a test"); " m+ d+ b0 W: [
5 e, G% c  o4 d. K& {
  方法四,使用CComBSTR。例如:
$ Z/ p- ^" k* v+ m5 g& V$ P, Q
4 a) k4 i( l. W" I, v1 u5 G/ mBSTR bstrText = CComBSTR("This is a test");
8 @5 m5 e" P) ^0 L" w* ~" v/ N
  或' ~2 Z. W4 I9 R6 Q8 m5 A& s$ Q$ _
8 L# }/ w# ]. ?/ T5 H1 r
CComBSTR bstr("This is a test");7 ~: Z! E' L7 Q, T: {
BSTR bstrText = bstr.m_str; 7 B. j( p. E2 v4 z  z& K6 v1 i

" ~$ o+ a- C4 |2 h6 Y; r; ^  方法五,使用ConvertStringToBSTR。例如:. a0 m) o& N( `0 F% ^4 L* q* a

0 `4 a7 K, S" Y5 m% Wchar* lpszText = "Test";7 `2 N. y7 E& s* _+ d+ @
BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText); + E+ l' _3 G" P" F+ V0 L

# C! q8 ?1 Z' r' T. A' `0 u  (5) CString转换成BSTR' A% I7 A; j& u" |; q5 P; A5 x0 P
( S( T. ]+ ]0 R/ k" M
  通常是通过使用CStringT::AllocSysString来实现。例如:0 p8 M; R+ E, j+ i, L5 F, M( N

& `0 ~  ~: p* e$ M, [CString str("This is a test");
8 U- _% F: n) P- UBSTR bstrText = str.AllocSysString();4 A1 I0 _& @7 B# z# `
" @+ Q! p) R3 d2 }5 x9 B- J5 m; e3 y
SysFreeString(bstrText); // 用完释放  
0 M0 F& h2 O( b/ v9 p. q
( b" x: u  N5 h7 S" V  (6) BSTR转换成CString
9 w. s# O/ N& X# Z! L6 e* v9 P3 \
6 }, v( B3 O1 c" v. f+ x$ {6 j  一般可按下列方法进行:0 f4 y$ Z& N; e  g4 ^7 V- B

5 j5 B' R! y' H! f; ABSTR bstrText = ::SysAllocString(L"Test");
3 C' {+ k/ K1 _CStringA str;
/ a: ^5 P" x' d# t! [str.Empty();
- S; u- k% F$ i% B( p1 nstr = bstrText;  
0 v8 }: \  N# i2 d5 m3 w6 P6 P7 V. D6 E; p, v* m
  或
# f* w4 j( R* D
0 z9 v! v* I9 q/ [* |  ZCStringA str(bstrText);
* W1 h+ h1 A6 Q' \* \% q3 R
* n- ?& r; `, N7 a  (7) ANSI、Unicode和宽字符之间的转换
9 [4 l+ U. G5 q1 ]
% d9 Z0 b0 F+ I- V, U  G  g  方法一,使用MultiByteToWideChar将ANSI字符转换成Unicode字符,使用WideCharToMultiByte将Unicode字符转换成ANSI字符。# l7 X. {& f6 ]6 k% X( u

7 q& `* E* m2 b( v) v2 C  方法二,使用“_T”将ANSI转换成“一般”类型字符串,使用“L”将ANSI转换成Unicode,而在托管C++环境中还可使用S将ANSI字符串转换成String*对象。例如:
. u/ f: v) X- l' b, }  \+ E& @5 ~$ Q; `+ J3 a& F8 `0 n
TCHAR tstr[] = _T("this is a test");( ~1 R; |, F9 m! e
wchar_t wszStr[] = L"This is a test";
! i( S, Y2 A, W  P" ~String* str = S”This is a test”;
0 ]/ ?  s8 t  L7 F( r" h! M& w; t0 f- V1 M( `$ r- H) d
  方法三,使用ATL 7.0的转换宏和类。ATL7.0在原有3.0基础上完善和增加了许多字符串转换宏以及提供相应的类,它具有如图3所示的统一形式:
$ c/ k2 Z1 x( _3 G+ A+ ^7 i$ s
1 c1 b$ K% o- d  其中,第一个C表示“类”,以便于ATL 3.0宏相区别,第二个C表示常量,2表示“to”,EX表示要开辟一定大小的缓冲。SourceType和DestinationType可以是A、T、W和OLE,其含义分别是ANSI、Unicode、“一般”类型和OLE字符串。例如,CA2CT就是将ANSI转换成一般类型的字符串常量。下面是一些示例代码:3 z1 h4 n- E+ ?/ Q2 o+ ?! e
# A% |5 h  t7 ]
LPTSTR tstr= CA2TEX<16>("this is a test");- i0 O$ X/ X5 t$ V
LPCTSTR tcstr= CA2CT("this is a test");
0 n& C: @+ |& l* ^# M: dwchar_t wszStr[] = L"This is a test";
) w1 b( }; j& v2 Q9 r) h, F  fchar* chstr = CW2A(wszStr);  
1 C; [& V% C8 i8 z1 }5 W/ |, l" U
: y- D* H6 ~! t; K  六、结语$ C" T& [9 b4 V- ~" [' [
0 v  J  Y+ |3 |% M
  几乎所有的程序都要用到字符串,而Visual C++.NET由于功能强大、应用广泛,因而字符串之间的转换更为频繁。本文几乎涉及到目前的所有转换方法。当然对于.NET框架来说,还可使用Convert和Text类进行不同数据类型以及字符编码之间的相互转换。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2025-5-5 09:21 , Processed in 0.014737 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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