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

常用数据类型使用转换详解

[复制链接]
发表于 2003-10-19 13:17:07 | 显示全部楼层 |阅读模式
作者:程佩君. S: c. f  I3 C( Q1 S/ L* d

7 ]! W. J, G6 c8 Z- w& T  V+ x7 s5 ?  V刚接触VC编程的朋友往往对许多数据类型的转换感到迷惑不解,本文将介绍一些常用数据类型的使用。* M( w- y& Y* g8 H

. t. Q0 X. p8 [7 e4 c我们先定义一些常见类型变量借以说明
7 o$ g$ j6 D" T8 P. K+ J7 a9 p1 a  \: n  x' [- l/ r
int i = 100;
6 `, r. j5 d5 ]1 V( w, O8 Tlong l = 2001;
2 G/ Q3 V" J$ p+ l% T4 Vfloat f=300.2;
8 R  j* u2 J8 y+ ?1 {double d=12345.119;
; \: i3 \2 T7 F0 M+ ~4 f$ Ichar username[]="程佩君";
+ h2 H' H* E- ~, a$ `& s# T2 m+ L3 Tchar temp[200];# z+ w" C! W1 ^7 H. Y" q9 p! y
char *buf;/ [! C" I  V' I2 g* i" _
CString str;, n$ n+ s" @+ o2 U6 r8 ^! \
_variant_t v1;
/ p% Z, l" X) r& E- [_bstr_t v2;
" [8 Z/ }. [3 R/ C3 j
' b* \- F) C  b# g3 d/ c1 J一、其它数据类型转换为字符串
5 j! i  @* M2 c7 q4 O, R  g
5 {1 {+ y6 ^3 x7 x; j/ e7 i& V3 \, ]5 ]9 B
短整型(int)
) }# _/ b) p+ Y$ I9 {6 Citoa(i,temp,10);///将i转换为字符串放入temp中,最后一个数字表示十进制
. @& @! w. H; W; A8 witoa(i,temp,2); ///按二进制方式转换
+ l: p+ T& j. f3 P/ ?- L长整型(long). J; }& g! ?1 b( V$ D
ltoa(l,temp,10); - b4 O: `6 X8 D: K; {4 F8 Y
浮点数(float,double)
6 r+ K: I6 U3 p6 q用fcvt可以完成转换,这是MSDN中的例子:
! J2 Q. e7 }# s- uint decimal, sign; ' x! \, k4 S; {$ A' Z
char *buffer; 6 P( [: j9 d; n
double source = 3.1415926535; $ b) a4 x) Y3 `- ?! n9 p
buffer = _fcvt( source, 7, &decimal, &sign );
+ t" ^- C$ k0 ^8 d/ N运行结果:source: 3.1415926535 buffer: '31415927' decimal: 1 sign: 02 H  P, j8 Y! t2 q
decimal表示小数点的位置,sign表示符号:0为正数,1为负数
4 i# ^6 H; ?  G& VCString变量
2 k: `  j8 N8 l' y. V  ^str = "2008北京奥运";& G7 A+ m- y) R& h3 j, f: ~( x9 z" N
buf = (LPSTR)(LPCTSTR)str; + v9 ]' e8 h0 S& }8 u- Z( @( O
BSTR变量
- N+ Y% o/ }' X8 HBSTR bstrValue = ::SysAllocString(L"程序员");
2 d% |/ `& g$ A: Y. U, }& Hchar * buf = _com_util::ConvertBSTRToString(bstrValue); " _3 v# {# k# G4 l2 ]) ]
SysFreeString(bstrValue);
% ~/ F5 f7 @8 i1 ~AfxMessageBox(buf); 7 s7 u- r7 e# w
delete(buf); ; d# q6 \0 `' F3 K
CComBSTR变量
/ E* x5 `1 u4 [- k1 I* b8 x7 W9 xCComBSTR bstrVar("test");
' }" R' n9 S- \( k6 ^( H* Dchar *buf = _com_util::ConvertBSTRToString(bstrVar.m_str); ! Y, s2 T+ v4 W- y) t' j' V
AfxMessageBox(buf); 4 m( a# `+ ^( u* N4 M
delete(buf);
, A* t& e. d1 m( S& c! E, _
5 N$ s: e  M' V& T& F_bstr_t变量
9 m8 B0 M! u/ }_bstr_t类型是对BSTR的封装,因为已经重载了=操作符,所以很容易使用
' _. E# o  k, ^  q# m3 b_bstr_t bstrVar("test");
( r# N7 s7 x+ N) e0 Econst char *buf = bstrVar;///不要修改buf中的内容
' l# e% \7 V, |4 h  JAfxMessageBox(buf); 7 |  t% f" f4 V: h( v

" D: Y$ w3 ]6 U! P/ k6 q" @7 e6 X: x% ~$ ?
通用方法(针对非COM数据类型): C) z1 v8 P* _' h" B
用sprintf完成转换1 d4 a7 f1 e7 V. v1 X  u5 R$ ?
char  buffer[200];. s% C4 J3 q' t$ }
char  c = '1';; [: t6 K$ D8 \- ?& c7 s
int   i = 35;* T0 O  @0 q. I7 s6 d7 N
long  j = 1000;/ D: a6 n! s- r$ N
float f = 1.7320534f;: n+ b4 @4 |( N3 N2 [/ {) V
sprintf( buffer, "%c",c);
# h6 B- _9 r) w- csprintf( buffer, "%d",i);% _1 b/ d. \! z8 {) M. M; z+ l
sprintf( buffer, "%d",j);7 [9 s6 o5 v( N) k$ p9 q
sprintf( buffer, "%f",f);3 \5 |2 K2 J& V6 a

1 O9 c" j, Z6 g& A: g- P6 d二、字符串转换为其它数据类型
* ?2 t, n  T; W2 M' Y! K4 s: estrcpy(temp,"123"); - E8 {5 C! v6 J7 B4 b

7 {0 R- W" f0 Q, c9 ]1 y短整型(int)
! N; ^4 A# H* ai = atoi(temp); " v' E  X4 x$ Z) C$ P
长整型(long)6 z9 ]# K8 y& e9 f& Q) N- P
l = atol(temp);
% Z, A  x* {# [浮点(double)" Q% d! h: A5 M: `, D5 {  ~
d = atof(temp); 4 W5 p" ^( f  Q; f0 L& J
CString变量- @7 E$ K8 L" G. L# g5 {
CString name = temp;
: |: T& a3 D, DBSTR变量 : T. F  }5 @; c! l; l
BSTR bstrValue = ::SysAllocString(L"程序员");
) x# w( ^& d- y; }* R% c% U4 J...///完成对bstrValue的使用
5 n* K; N, F) e0 a3 ~SysFreeString(bstrValue); 8 a! }+ A2 \! z4 Q9 o7 `
# ]2 {  n+ ]) |/ x4 Y
CComBSTR变量. c- ?' b- t8 M0 ^8 r
CComBSTR类型变量可以直接赋值
7 I6 [0 T7 o$ h* D& ]/ J  X0 UCComBSTR bstrVar1("test");
* t5 T+ [6 O3 t, r0 VCComBSTR bstrVar2(temp);$ R' C1 x! O9 e

/ \. e2 e5 @. V2 k# i/ N8 d_bstr_t变量
. z+ \3 i5 M7 D  L+ V( }) h6 X- Q0 v_bstr_t类型的变量可以直接赋值
$ A* K$ l2 _8 d- g_bstr_t bstrVar1("test"); . @$ o+ [5 X) Z9 [0 J4 b
_bstr_t bstrVar2(temp); ( @# G4 N. |1 b" T/ C

1 J7 P! R3 _0 T- [" q6 H! ]
1 W" G8 `' y1 l* O三、其它数据类型转换到CString7 X7 h7 F4 O! R+ D+ R2 J
使用CString的成员函数Format来转换,例如:6 U" Z! h) T, s

, `! {% u9 A  d5 G' h/ p8 K6 M- u4 d6 j
整数(int)
: U5 x& k- |$ F. W& S$ mstr.Format("%d",i);
: `' n6 @! [' P) H浮点数(float)
" V* l- P2 w% d# g: ~1 Wstr.Format("%f",i);
, g6 p/ x# W; C$ f4 H  `1 f字符串指针(char *)等已经被CString构造函数支持的数据类型可以直接赋值+ A6 a; Q+ L* `6 Y. b
str = username;
7 M% d& f' m3 R7 y对于Format所不支持的数据类型,可以通过上面所说的关于其它数据类型转化到char *的方法先转到char *,然后赋值给CString变量。8 _6 q4 R5 h0 I. Y* H# R
9 l5 H/ y, p4 e3 C
四、BSTR、_bstr_t与CComBSTR
: U1 J5 P8 k3 ]/ S* o8 Z! z, K: d7 i" z  \- h
) q' w* x# m( v! j) O. z$ D: ^7 E, J
CComBSTR 是ATL对BSTR的封装,_bstr_t是C++对BSTR的封装,BSTR是32位指针,但并不直接指向字串的缓冲区。6 D$ @+ c5 q) u' Q  D
char *转换到BSTR可以这样:
! ^) T2 L) i8 z" N5 P0 wBSTR b=_com_util::ConvertStringToBSTR("数据");///使用前需要加上comutil.h和comsupp.lib
' D$ W  m/ `" D6 q, uSysFreeString(bstrValue);
0 \) [& N2 U' A' Z  v反之可以使用
+ X( @+ k* u9 X. D% w( t  Pchar *p=_com_util::ConvertBSTRToString(b);& [# r' Z7 m7 C& a* r$ K
delete p;
' Y. U5 C2 B) m# [2 [- C3 c具体可以参考一,二段落里的具体说明。
) y% U1 f: y* `9 U" ]2 ?
. _" A0 N  f, G' w5 jCComBSTR与_bstr_t对大量的操作符进行了重载,可以直接进行=,!=,==等操作,所以使用非常方便。
3 z( k6 S% s( }' l6 J+ _( b特别是_bstr_t,建议大家使用它。
" Y. U) i0 y% |* C( d  a1 f+ @, n9 Q7 t( a8 j" b

& p' m- {# G/ U* X- r( N五、VARIANT 、_variant_t 与 COleVariant
  x. h  ~$ i5 G/ ?5 z) ?
# M" A$ F) n/ |  i$ u4 g# Y8 b' Y. `
VARIANT的结构可以参考头文件VC98\Include\OAIDL.H中关于结构体tagVARIANT的定义。
9 c2 Y5 T* Z& ^& m( A. g+ v对于VARIANT变量的赋值:首先给vt成员赋值,指明数据类型,再对联合结构中相同数据类型的变量赋值,举个例子:
3 Y" F9 j" Q, T. l; AVARIANT va;8 c! ^. T6 L1 q. b
int a=2001;
+ n2 x3 i" D1 d* i  N6 E2 O3 G, E# f" bva.vt=VT_I4;///指明整型数据5 W" g) J" P# T
va.lVal=a; ///赋值) T* S  I3 o8 \( D/ {5 ?, B  _
' j/ E4 Y5 @4 D+ Q1 B
对于不马上赋值的VARIANT,最好先用Void VariantInit(VARIANTARG FAR* pvarg);进行初始化,其本质是将vt设置为VT_EMPTY,下表我们列举vt与常用数据的对应关系:6 l8 T+ G/ n6 D) n7 w. ]* T
& `* S9 y: _5 i$ |: }  f7 [* E# X
Byte bVal;  // VT_UI1. $ q4 H2 r. t0 A) g
Short iVal;  // VT_I2. ' J, j  R( l: t. P+ \' F
long lVal;  // VT_I4.
1 A* _6 V# Q: z: k: Afloat fltVal;  // VT_R4.
: ^; _7 I( `# C8 B9 h/ y, adouble dblVal;  // VT_R8. 9 y' N/ ]1 a1 ~) l3 G
VARIANT_BOOL boolVal;  // VT_BOOL.
  m5 A; U) `- Q/ kSCODE scode;  // VT_ERROR.
2 f: T& T* a8 `* w* ?. L7 WCY cyVal;  // VT_CY.
9 j) Q+ E8 V( w+ q  T# D5 @. TDATE date;  // VT_DATE. 5 G& {: r4 V, ~
BSTR bstrVal;  // VT_BSTR. ; x7 K3 L' L4 d0 U
DECIMAL FAR* pdecVal  // VT_BYREF|VT_DECIMAL. , F8 N4 h/ i4 R+ a$ l4 W
IUnknown FAR* punkVal;  // VT_UNKNOWN.
  D) q2 Z0 h* p  V8 P5 PIDispatch FAR* pdispVal;  // VT_DISPATCH. 0 g1 S) Y) S: G& H! u$ y' d2 p
SAFEARRAY FAR* parray;  // VT_ARRAY|*. , Z, @& m8 H# q/ D3 ?0 F. v
Byte FAR* pbVal;  // VT_BYREF|VT_UI1.   T# p  B6 a% Z2 L% `
short FAR* piVal;  // VT_BYREF|VT_I2. " F  i. w: o0 Z( ?4 {- _
long FAR* plVal;  // VT_BYREF|VT_I4.
4 c3 q. {: f1 G) O5 Pfloat FAR* pfltVal;  // VT_BYREF|VT_R4.
- c6 C3 J/ a3 i9 d) W( |double FAR* pdblVal;  // VT_BYREF|VT_R8.
' }: x- f' z( J  l+ r" cVARIANT_BOOL FAR* pboolVal;  // VT_BYREF|VT_BOOL. 6 R# z$ _/ b0 J8 u% l& p
SCODE FAR* pscode;  // VT_BYREF|VT_ERROR.
2 o4 _9 a. t, X# q; F+ h' TCY FAR* pcyVal;  // VT_BYREF|VT_CY.
+ x9 q; e2 r' @# ^2 I4 KDATE FAR* pdate;  // VT_BYREF|VT_DATE.   o; M$ Z+ V$ t1 [0 ~4 Z6 J
BSTR FAR* pbstrVal;  // VT_BYREF|VT_BSTR. " D& s2 S/ z3 i9 d
IUnknown FAR* FAR* ppunkVal;  // VT_BYREF|VT_UNKNOWN.
% ~# Q& S/ ~8 S* `; nIDispatch FAR* FAR* ppdispVal;  // VT_BYREF|VT_DISPATCH.
# c9 S3 ~6 S# C) {2 k+ [SAFEARRAY FAR* FAR* pparray;  // VT_ARRAY|*.
. d3 m# B! \( C% v. mVARIANT FAR* pvarVal;  // VT_BYREF|VT_VARIANT. 1 i$ W( f! n0 B% E" ]( ?8 Q  a
void FAR* byref;  // Generic ByRef. 9 b0 A! d; i7 m; P5 w# e1 G* i
char cVal;  // VT_I1. * E8 V3 w- E& K* d) w" U
unsigned short uiVal;  // VT_UI2.
- u8 \( ?& [1 C+ Lunsigned long ulVal;  // VT_UI4.
. O1 ^8 Q! ?% y7 B, _int intVal;  // VT_INT.
' ^1 m8 ^6 `* |! j3 kunsigned int uintVal;  // VT_UINT.
7 |, A* v  y- h# M' u. ychar FAR * pcVal;  // VT_BYREF|VT_I1. # z% v2 b. Z% L* _8 m
unsigned short FAR * puiVal;  // VT_BYREF|VT_UI2.
+ {4 b; U& l; |5 @8 C& z4 o/ B- Ounsigned long FAR * pulVal;  // VT_BYREF|VT_UI4. 6 ?$ K8 S7 k! y' a# Z+ A: Z/ p! R1 `0 e
int FAR * pintVal;  // VT_BYREF|VT_INT. $ \! e, L+ \$ n: T2 ^- f
unsigned int FAR * puintVal;  //VT_BYREF|VT_UINT. 5 m/ |3 m3 ]! z& B  b; {9 V3 a

( H2 M7 h$ b& O0 K# ^0 V
' L* H1 G  F5 ^_variant_t是VARIANT的封装类,其赋值可以使用强制类型转换,其构造函数会自动处理这些数据类型。
7 [9 y4 ~( }6 o5 D, k7 {6 Y使用时需加上#include <comdef.h>
* y+ t2 t' X2 l* d4 a例如:
  A7 Q' D( k( U! _7 Flong l=222;
) [" S" i4 R0 P5 fing i=100;
: F  I$ s+ S" S3 S_variant_t lVal(l);  i  d0 ?5 q1 V. M* w
lVal = (long)i;
# L! p* b* W( n) V) i8 F; ~( y5 \! g+ g" k; l! {

! ]/ B  r) k# ~! ~" pCOleVariant的使用与_variant_t的方法基本一样,请参考如下例子:  y. w( e& i$ i* s" z
COleVariant v3 = "字符串", v4 = (long)1999;
0 B* ~7 K; |$ k/ n# T5 x7 a  ~CString str =(BSTR)v3.pbstrVal;
' L* k1 ~1 j& q, g8 Z, jlong i = v4.lVal;) p/ V  c5 z4 k8 f# Q1 `
3 X! M9 J' R# M3 Y
- j4 ?- g- M  h8 B* `
六、其它一些COM数据类型9 e% ?. w0 d. ~1 K# l# o% ?

' y' |  T+ k8 r4 [1 ^根据ProgID得到CLSID
/ [; W9 @8 V/ _6 [2 _HRESULT CLSIDFromProgID( LPCOLESTR lpszProgID,LPCLSID pclsid);1 O7 a# W/ Z" t& d
CLSID clsid;
* W+ m, g6 }/ YCLSIDFromProgID( L"MAPI.Folder",&clsid);  [- p% @- I. ]8 ~1 ]% m$ G

+ ^. V- G* p7 h2 |2 ^3 g4 A8 I根据CLSID得到ProgID
2 n% ?5 B7 i- O% O6 kWINOLEAPI ProgIDFromCLSID( REFCLSID clsid,LPOLESTR * lplpszProgID);
6 I% I' L4 {1 a7 E. i' L例如我们已经定义了 CLSID_IApplication,下面的代码得到ProgID$ g* x/ M# I; S. g) c
LPOLESTR pProgID = 0;+ H( I% z. L2 e$ L: r% ?/ b2 n
ProgIDFromCLSID( CLSID_IApplication,&pProgID);
5 i! r! X9 _' K0 {/ X$ k: s6 L- {...///可以使用pProgID ) P. a* j! K. V, ~! G7 y( g/ X
CoTaskMemFree(pProgID);//不要忘记释放 ) o0 h- X4 W' E3 W' O3 {+ B

6 h& u% L: |! R. H: P; B2 \七、ANSI与Unicode
2 ]- l) L- J9 S! e- wUnicode称为宽字符型字串,COM里使用的都是Unicode字符串。
& n+ K% q2 }8 t* G/ C/ q0 T& ]: L* ]7 t1 B7 Z( V
将ANSI转换到Unicode" I( @& n9 ?5 e: J
(1)通过L这个宏来实现,例如: CLSIDFromProgID( L"MAPI.Folder",&clsid);
( R' o$ y& i, h% A(2)通过MultiByteToWideChar函数实现转换,例如:
* S- u$ q/ T8 _( w- ochar *szProgID = "MAPI.Folder";! K# i) @% k( ]' p& J
WCHAR szWideProgID[128];
" T4 P: ?4 y/ HCLSID clsid;
- l' x+ P  D- @long lLen = MultiByteToWideChar(CP_ACP,0,szProgID,strlen(szProgID),szWideProgID,sizeof(szWideProgID));$ |( {! D- [7 v3 W; X
szWideProgID[lLen] = '\0'; ' A/ e9 p  W0 T1 i; Z
(3)通过A2W宏来实现,例如:
$ I& I! S1 ]$ j( y; g- TUSES_CONVERSION;
. F5 E; I3 G# @) VCLSIDFromProgID( A2W(szProgID),&clsid); 7 D3 d5 i3 {& p. f9 y
将Unicode转换到ANSI
, Y3 z! a2 e# v! G(1)使用WideCharToMultiByte,例如:* A$ C, |( ]2 N2 \
// 假设已经有了一个Unicode 串 wszSomeString...
( u4 y* d& }2 }char szANSIString [MAX_PATH]; * U2 g; J+ i2 G1 y; t1 i6 l
WideCharToMultiByte ( CP_ACP, WC_COMPOSITECHECK, wszSomeString, -1, szANSIString, sizeof(szANSIString), NULL, NULL ); . N4 B& z1 A! O5 w6 |4 m/ S9 c3 c; X
(2)使用W2A宏来实现,例如:3 D+ {. W- j; u* ~0 c: U
USES_CONVERSION;
, T, X$ w6 v4 R0 bpTemp=W2A(wszSomeString); # E$ k* P) ]3 `0 q( U
八、其它
: g5 R9 ~$ L! a! \& j$ p0 i1 E. Q% M: t2 e/ S- _
对消息的处理中我们经常需要将WPARAM或LPARAM等32位数据(DWORD)分解成两个16位数据(WORD),例如:' N- p4 V+ }! t* U% x, h# F
LPARAM lParam;
/ W# b4 j" ], Q! \1 _8 CWORD loValue = LOWORD(lParam);///取低16位
1 |+ R8 N3 u7 ?' F: Z! x2 |: {0 hWORD hiValue = HIWORD(lParam);///取高16位7 A/ x0 h2 Q4 {9 a2 c

( F" y& {- G  M+ n6 i+ M
8 s8 `% W7 Y( ]" l7 N: [' i对于16位的数据(WORD)我们可以用同样的方法分解成高低两个8位数据(BYTE),例如:
+ L  x' w4 Z" Z4 D+ P5 \WORD wValue;
2 o" K3 {8 |. J3 y1 @# IBYTE loValue = LOBYTE(wValue);///取低8位
5 d2 K: F% N, |BYTE hiValue = HIBYTE(wValue);///取高8位
2 `! o, p$ d( E" {/ `* Z) c9 {: }) G6 |9 e6 d8 A
, k$ ?+ [$ [7 e  [% s
两个16位数据(WORD)合成32位数据(DWORD,LRESULT,LPARAM,或WPARAM)" w8 _. y# B: o( ]% n, Z
LONG MAKELONG( WORD wLow, WORD wHigh );
' K) ]7 m# U) t& M, A$ e( z% u+ K$ UWPARAM MAKEWPARAM( WORD wLow, WORD wHigh ); ! V6 W8 J( w: X5 u% z8 m
LPARAM MAKELPARAM( WORD wLow, WORD wHigh );" c/ M% e6 q, A. l
LRESULT MAKELRESULT( WORD wLow, WORD wHigh ); , w4 c8 u! h! U  M. M

. f# |: G1 s$ \6 q7 |
$ }' a$ N; H& o$ s9 s两个8位的数据(BYTE)合成16位的数据(WORD). g3 }7 e7 m; D# l
WORD MAKEWORD( BYTE bLow, BYTE bHigh );
) W* @  |: ^2 q& `7 p+ d6 I6 k
% Q* J9 S5 p$ x) n  e! @9 S# ?* ?# i8 b* ?  U' e
从R(red),G(green),B(blue)三色得到COLORREF类型的颜色值
4 F* y2 w$ B$ M" tCOLORREF RGB( BYTE byRed,BYTE byGreen,BYTE byBlue );
$ Y# W' d8 L0 @% t+ L6 A例如COLORREF bkcolor = RGB(0x22,0x98,0x34);
9 o: H  T  S5 a) k1 V/ ?" j
" ^1 r6 J1 T/ o6 s; W$ L+ c1 b
6 g9 I7 S2 N/ L" `1 l8 l4 w从COLORREF类型的颜色值得到RGB三个颜色值7 E7 [" X$ q, d' Z8 H+ ^* t
BYTE Red = GetRValue(bkcolor); ///得到红颜色5 }% M& i9 W0 K4 S7 t: U8 D
BYTE Green = GetGValue(bkcolor); ///得到绿颜色0 \0 F9 ]1 @/ B& q0 Z4 }9 Q7 A7 f
BYTE Blue = GetBValue(bkcolor); ///得到兰颜色
4 s4 z! `( v' `! q$ E
3 G  w" O$ Y; |2 c% T九、注意事项. }# x7 S6 s8 f  V0 [- j$ D/ E- E
假如需要使用到ConvertBSTRToString此类函数,需要加上头文件comutil.h,并在setting中加入comsupp.lib或者直接加上#pragma comment( lib, "comsupp.lib" )
1 C" P8 L2 v7 q) Z: y; ?" ^2 ?) X& [2 r+ {
后记:本文匆匆写成,错误之处在所难免,欢迎指正.
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2025-6-20 06:06 , Processed in 0.037056 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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