??xml version="1.0" encoding="utf-8" standalone="yes"?>国产亚洲美女精品久久久,久久久久亚洲AV成人网人人网站,伊人久久亚洲综合影院http://www.shnenglu.com/brucejini/category/12062.htmlzh-cnThu, 24 Dec 2009 14:07:09 GMTThu, 24 Dec 2009 14:07:09 GMT60VC常用数据cd使用转换详解(转蝲) http://www.shnenglu.com/brucejini/articles/103947.html路h?/dc:creator>路h?/author>Thu, 24 Dec 2009 07:52:00 GMThttp://www.shnenglu.com/brucejini/articles/103947.htmlhttp://www.shnenglu.com/brucejini/comments/103947.htmlhttp://www.shnenglu.com/brucejini/articles/103947.html#Feedback0http://www.shnenglu.com/brucejini/comments/commentRss/103947.htmlhttp://www.shnenglu.com/brucejini/services/trackbacks/103947.htmlCString ,BSTR ,LPCTSTR之间关系和区?/font>

CString是一个动态TCHAR数组QBSTR是一U专有格式的字符Ԍ需要用pȝ提供的函数来操纵QLPCTSTR只是一个常量的TCHAR指针?br>
CString 是一个完全独立的c,动态的TCHAR数组Q封装了 + {操作符和字W串操作Ҏ(gu)?br>typedef OLECHAR FAR* BSTR;
typedef const char * LPCTSTR;

vc++中各U字W串的表C法

首先char* 是指向ANSI字符数组的指针,其中每个字符占据8位(有效数据是除掉最高位的其?位)Q这里保持了与传l的C,C++的兼宏V?/p>

LP的含义是长指?long pointer)。LPSTR是一个指向以‘\0’l尾的ANSI字符数组的指针,与char*可以互换使用Q在win32中较多地使用LPSTR?br>而LPCSTR中增加的‘C’的含义是“CONSTANT”Q常量)Q表明这U数据类型的实例不能被用它的API函数改变Q除此之外,它与LPSTR是等同的?br>1.LP表示长指?在win16下有长指?LP)和短指针(P)的区?而在win32下是没有区别?都是32?所以这里的LP和P是等L.
2.C表示const
3.T是什么东西呢,我们知道TCHAR在采用Unicode方式~译时是wchar_t,在普通时~译成char.

Z满E序代码国际化的需要,业界推出了Unicode标准Q它提供了一U简单和一致的表达字符串的Ҏ(gu)Q所有字W中的字节都?6位的|其数量也可以满差不多世界上所有书面语a字符的编码需求,开发程序时使用UnicodeQ类型ؓwchar_t)是一U被鼓励的做法?/p>

LPWSTR与LPCWSTR由此产生Q它们的含义cM于LPSTR与LPCSTRQ只是字W数据是16位的wchar_t而不是char?/p>

然后Z实现两种~码的通用Q提ZTCHAR的定义:
如果定义_UNICODEQ声明如下:
typedef wchar_t TCHAR;
如果没有定义_UNICODEQ则声明如下Q?br>typedef char TCHAR;

LPTSTR和LPCTSTR中的含义是每个字符是这LTCHAR?/p>

CStringcM的字W就是被声明为TCHARcd的,它提供了一个封装好的类供用h便地使用?/p>

LPCTSTR:
     #ifdef _UNICODE
        typedef const wchar_t * LPCTSTR;
     #else
        typedef const char * LPCTSTR;
     #endif

VC常用数据cd使用转换详解
 
先定义一些常见类型变量借以说明
int i = 100;
long l = 2001;
float f=300.2;
double d=12345.119;
char username[]="女侠E佩?;
char temp[200];
char *buf;
CString str;
_variant_t v1;
_bstr_t v2;

一、其它数据类型{换ؓ字符?/font>

短整?int)
       itoa(i,temp,10);     //i转换为字W串攑օtemp?最后一个数字表C十q制
       itoa(i,temp,2);      //按二q制方式转换
长整?long)
       ltoa(l,temp,10);


二、从其它包含字符串的变量中获取指向该字符串的指针

CString变量
str = "2008北京奥运";
buf = (LPSTR)(LPCTSTR)str;
BSTRcd的_variant_t变量
v1 = (_bstr_t)"E序?;
buf = _com_util::ConvertBSTRToString((_bstr_t)v1);

三、字W串转换为其它数据类?br>strcpy(temp,"123");

短整?int)
      i = atoi(temp);
长整?long)
      l = atol(temp);
点(double)
      d = atof(temp);

四、其它数据类型{换到CString

使用CString的成员函数Format来{?例如:

整数(int)
      str.Format("%d",i);
点?float)
      str.Format("%f",i);
字符串指?char *){已l被CString构造函数支持的数据cd可以直接赋?br>      str = username;

五、BSTR、_bstr_t与CComBSTR

CComBSTR、_bstr_t是对BSTR的封?BSTR是指向字W串?2位指针?br>char *转换到BSTR可以q样: BSTR b=_com_util::ConvertStringToBSTR("数据");     //使用前需要加上头文gcomutil.h
反之可以使用char *p=_com_util::ConvertBSTRToString(b);


六、VARIANT 、_variant_t ?COleVariant

VARIANT的结构可以参考头文gVC98\Include\OAIDL.H中关于结构体tagVARIANT的定义?br>对于VARIANT变量的赋|首先lvt成员赋|指明数据cdQ再对联合结构中相同数据cd的变量赋|举个例子Q?br>VARIANT va;
int a=2001;
va.vt=VT_I4;    //指明整型数据
va.lVal=a;      //赋?/p>

对于不马上赋值的VARIANTQ最好先用Void VariantInit(VARIANTARG FAR* pvarg);q行初始?其本质是vt讄为VT_EMPTY,下表我们列Dvt与常用数据的对应关系:

unsigned char bVal; VT_UI1
short iVal; VT_I2
long lVal;  VT_I4 
float fltVal;  VT_R4
double dblVal;  VT_R8 
VARIANT_BOOL boolVal;  VT_BOOL
SCODE scode;  VT_ERROR
CY cyVal;  VT_CY
DATE date;  VT_DATE
BSTR bstrVal;  VT_BSTR
IUnknown FAR* punkVal;  VT_UNKNOWN
IDispatch FAR* pdispVal;  VT_DISPATCH
SAFEARRAY FAR* parray;  VT_ARRAY|*
unsigned char FAR* pbVal;  VT_BYREF|VT_UI1
short FAR* piVal;  VT_BYREF|VT_I2
long FAR* plVal;  VT_BYREF|VT_I4
float FAR* pfltVal;  VT_BYREF|VT_R4
double FAR* pdblVal; VT_BYREF|VT_R8
VARIANT_BOOL FAR* pboolVal; VT_BYREF|VT_BOOL
SCODE FAR* pscode;  VT_BYREF|VT_ERROR
CY FAR* pcyVal;  VT_BYREF|VT_CY
DATE FAR* pdate; VT_BYREF|VT_DATE
BSTR FAR* pbstrVal;  VT_BYREF|VT_BSTR
IUnknown FAR* FAR* ppunkVal;  VT_BYREF|VT_UNKNOWN
IDispatch FAR* FAR* ppdispVal; VT_BYREF|VT_DISPATCH
SAFEARRAY FAR* FAR* pparray;  VT_ARRAY|*
VARIANT FAR* pvarVal;  VT_BYREF|VT_VARIANT
void FAR* byref;  VT_BYREF

_variant_t是VARIANT的封装类Q其赋值可以用强制类型{换,其构造函C自动处理q些数据cd?br>例如Q?br>long l=222;
ing i=100;
_variant_t lVal(l);
lVal = (long)i;

COleVariant的用与_variant_t的方法基本一P请参考如下例子:
COleVariant v3 = "字符?, v4 = (long)1999;
CString str =(BSTR)v3.pbstrVal;
long i = v4.lVal;

七、其?/font>

Ҏ(gu)息的处理中我们经帔R要将WPARAM或LPARAM{?2位数?DWORD)分解成两?6位数?WORD),例如Q?br>LPARAM lParam;
WORD loValue = LOWORD(lParam);     //取低16?br>WORD hiValue = HIWORD(lParam);     //取高16?
对于16位的数据(WORD)我们可以用同LҎ(gu)分解成高低两?位数?BYTE),例如:
WORD wValue;
BYTE loValue = LOBYTE(wValue);     //取低8?br>BYTE hiValue = HIBYTE(wValue);     //取高8?nbsp;

如何CStringcd的变量赋lchar*cd的变?br>1、GetBuffer函数Q?br>使用CString::GetBuffer函数?br>char *p;
CString str="hello";
p=str.GetBuffer(str.GetLength());
str.ReleaseBuffer();

CString转换成char * ?br>CString str("aaaaaaa");
strcpy(str.GetBuffer(10),"aa");
str.ReleaseBuffer();
当我们需要字W数l时调用GetBuffer(int n),其中n为我们需要的字符数组的长?使用完成后一定要马上调用ReleaseBuffer();
q有很重要的一点就?在能使用const char *的地?׃要用char *

2、memcpyQ?
CString mCS=_T("cxl");
char mch[20];
memcpy(mch,mCS,20);

3、用LPCTSTR强制转换Q?量不?br>char *ch;
CString str;
ch=(LPSTR)(LPCTSTR)str;

CString str = "good";
char *tmp;
sprintf(tmp,"%s",(LPTSTR)(LPCTSTR)str);

4?br>CString Msg;
Msg=Msg+"abc";
LPTSTR lpsz;
lpsz = new TCHAR[Msg.GetLength()+1];
_tcscpy(lpsz, Msg);
char * psz;
strcpy(psz,lpsz);


CStringcdconst char *转换
char a[100];
CString str("aaaaaa");
strncpy(a,(LPCTSTR)str,sizeof(a));
或者如?
strncpy(a,str,sizeof(a));
以上两种用法都是正确? 因ؓstrncpy的第二个参数cd为const char *.所以编译器会自动将CStringc{换成const char *.

CString转LPCTSTR (const char *)
CString cStr;
const char *lpctStr=(LPCTSTR)cStr;

LPCTSTR转CString
LPCTSTR lpctStr;
CString cStr=lpctStr;

char*cd的变量赋lCString型的变量
可以直接赋|如:
CString myString = "This is a test";
也可以利用构造函敎ͼ如:
CString s1("Tom");

CStringcd的变量赋lchar []cd(字符?的变?br>1、sprintf()函数
CString str = "good";
char tmp[200] ;
sprintf(tmp, "%s",(LPCSTR)str);  
(LPCSTR)strq种强制转换相当?LPTSTR)(LPCTSTR)str
CStringcȝ变量需要{换ؓ(char*)的时,使用(LPTSTR)(LPCTSTR)str

然而,LPCTSTR是const char *,也就是说Q得到的字符串是不可写的Q将其强制{换成LPTSTRLconstQ是极ؓ危险的!
一不留就会完蛋!要得到char *,应该用GetBuffer()或GetBufferSetLength()Q用完后再调用ReleaseBuffer()?/p>

2、strcpy()函数
CString str;
char c[256];
strcpy(c, str);

char mychar[1024];
CString source="Hello";
strcpy((char*)&mychar,(LPCTSTR)source);


关于CString的?br>1、指?CString 形参
    对于大多数需要字W串参数的函敎ͼ最好将函数原型中的形参指定Z个指向字W?(LPCTSTR) 而非 CString ?const 指针?br>当将形参指定为指向字W的 const 指针Ӟ可将指针传递到 TCHAR 数组Q如字符?["hi there"]Q或传递到 CString 对象?br>CString 对象自动{换成 LPCTSTR。Q何能够?LPCTSTR 的地方也能够使用 CString 对象?/p>

2、如果某个Ş参将不会被修改,则也该参数指定为常数字W串引用Q即 const CString&Q。如果函数要修改该字W串Q?br>则删?const 修饰W。如果需要默认ؓI|则将其初始化为空字符?[""]Q如下所C:
void AddCustomer( const CString& name, const CString& address, const CString& comment = "" );

3、对于大多数函数l果Q按D?CString 对象卛_?/p>


串的基本q算
    对于串的基本q算Q很多高U语a均提供了相应的运符或标准的库函数来实现?br>为叙q方便,先定义几个相关的变量Q?br>    char s1[20]="dir/bin/appl",s2[20]="file.asm",s3[30],*p;
    int result;
    下面以C语言中串q算介绍串的基本q算
1、求串长
        int strlen(char *s);         //求串s的长?br>    【例】printf("%d",strlen(s1));    //输出s1的串?2

2、串复制
    char *strcpy(char *to,*from)Q?/from串复制到to串中Qƈq回to开始处指针
    【例】strcpy(s3,s1);  //s3="dir/bin/appl",s1串不?/p>


3、联?br>    char *strcat(char *to,char *from);//from串复制到to串的末尾Q?br>                                      //q返回to串开始处的指?br>    【例】strcat(s3,"/");    //s3="dir/bin/appl/"
         strcat(s3,s2);     //s3="dir/bin/appl/file.asm"

4、串比较
    int strcmp(char *s1,char *s2);//比较s1和s2的大,
     //当s1<s2、s1>s2和s1=s2Ӟ分别q回于0、大?和等?的?
    【例】result=strcmp("baker","Baker");    //result>0
            result=strcmp("12","12");       //result=0
            result=strcmp("Joe","joseph")   //result<0

5、字W定?br>    char *strchr(char *s,char c);//找c在字W串s中第一ơ出现的位置Q?br>                                 //若找刎ͼ则返回该位置Q否则返回NULL
    【例】p=strchr(s2,'.');      //p指向"file"之后的位|?br>     if(p) strcpy(p,".cpp");     //s2="file.cpp"

  注意Q?br>     ①上q操作是最基本的,其中?4个操作还有变UŞ式:strncpyQstrncath和strnchr?br>     ②其它的串操作见C?lt;string.h>。在不同的高U语a中,对串q算的种cdW号都不相?br>     ③其余的串操作一般可p些基本操作组合而成

    【例】求子串的操作可如下实现Q?br>    void substr(char *sub,char *s,int pos,int len){
         //s和sub是字W数l,用subq回串s的第pos个字Wv长度为len的子?br>         //其中0<=pos<=strlen(s)-1,且数lsub臛_可容Ulen+1个字W?br>        if (pos<0||pos>strlen(s)-1||len<0)
            Error("parameter error!");
        strncpy(sub,&s[pos],len);      //从s[pos]起复制至多len个字W到sub



]]>
CString 操作指南http://www.shnenglu.com/brucejini/articles/99017.html路h?/dc:creator>路h?/author>Tue, 20 Oct 2009 08:16:00 GMThttp://www.shnenglu.com/brucejini/articles/99017.htmlhttp://www.shnenglu.com/brucejini/comments/99017.htmlhttp://www.shnenglu.com/brucejini/articles/99017.html#Feedback0http://www.shnenglu.com/brucejini/comments/commentRss/99017.htmlhttp://www.shnenglu.com/brucejini/services/trackbacks/99017.html

CString 操作指南


原著QJoseph M. Newcomer

译Q?a href="mailto:littleloach@sina.com">littleloach

原文出处Q?a target="_blank" >codeprojectQCString Management


通过阅读本文你可以学习如何有效地使用 CString?br>
  CString 是一U很有用的数据类型。它们很大程度上化了MFC中的许多操作Q得MFC在做字符串操作的时候方便了很多。不怎样Q用CString有很多特D的技巧,特别是对于纯C背景下走出来的程序员来说有点难以学习。这文章就来讨些技巧?br>   使用CString可以让你对字W串的操作更加直截了当。这文章不是CString的完全手册,但囊括了大部分常见基本问题?br>
q篇文章包括以下内容Q?ol>

  • 格式化字W串Q包?int 型{化ؓ CString Q?/a>

  • CString 型和 char* cd的相互{?/a>
  • char* 转化?CString
  • CString 转化?char* 之一Q用LPCTSTR强制转化
  • CString 转化?char* 之二Q用CString对象的GetBufferҎ(gu)
  • CString 转化?char* 之三: 和控件的接口
  • BSTR 型{化成 CString ?/a>Q?/li>
  • 载入字符串表资源Q?/li>
  • CString 的效?/a>Q?/li>
  • ȝ
  • 下面我分别讨论?br>
    1?b>

    要比用下面的Ҏ(gu)好得多:

    char gray[] = "Gray";
    char cat[] = "Cat";
    char * graycat = malloc(strlen(gray) + strlen(cat) + 1);
    strcpy(graycat, gray);
    strcat(graycat, cat);

    2?b>格式化字W串

      与其?sprintf() 函数?wsprintf() 函数来格式化一个字W串Q还不如?CString 对象的Format()Ҏ(gu)Q?/p>

    CString s;
    s.Format(_T("The total is %d"), total);

      用这U方法的好处是你不用担心用来存放格式化后数据的缓冲区是否_大,q些工作由CStringcL你完成?br>   格式化是一U把其它不是字符串类型的数据转化为CStringcd的最常用技巧,比如Q把一个整数{化成CStringcdQ可用如下方法:

    CString s;
    s.Format(_T("%d"), total);

      我LҎ(gu)的字W串使用_T()宏,q是Z让我的代码至有Unicode的意识,当然Q关于Unicode的话题不在这文章的讨论范围。_T()宏在8位字W环境下是如下定义的Q?/p>

    #define _T(x) x // 非Unicode版本Qnon-Unicode versionQ?/pre>
          

    而在Unicode环境下是如下定义的:

    #define _T(x) L##x // Unicode版本QUnicode versionQ?/pre>
          

    所以在Unicode环境下,它的效果q当于Q?/p>

    s.Format(L"%d", total);

      如果你认Z的程序可能在Unicode的环境下q行Q那么开始在意用 Unicode ~码。比如说Q不要用 sizeof() 操作W来获得字符串的长度Q因为在Unicode环境下就会有2倍的误差。我们可以用一些方法来隐藏Unicode的一些细节,比如在我需要获得字W长度的时候,我会用一个叫做DIM的宏Q这个宏是在我的dim.h文g中定义的Q我会在我写的所有程序中都包含这个文Ӟ

    #define DIM(x) ( sizeof((x)) / sizeof((x)[0]) )
      q个宏不仅可以用来解决Unicode的字W串长度的问题,也可以用在编译时定义的表gQ它可以获得表格的项敎ͼ如下Q?br>
    class Whatever { ... };
    Whatever data[] = {
       { ... },
        ...
       { ... },
    };
    for(int i = 0; i < DIM(data); i++) // 扫描表格L匚wV?
    
      q里要提醒你的就是一定要注意那些在参C需要真实字节数的API函数调用Q如果你传递字W个数给它,它将不能正常工作。如下:
    TCHAR data[20];
    lstrcpyn(data, longstring, sizeof(data) - 1); // WRONG!
    lstrcpyn(data, longstring, DIM(data) - 1); // RIGHT
    WriteFile(f, data, DIM(data), &bytesWritten, NULL); // WRONG!
    WriteFile(f, data, sizeof(data), &bytesWritten, NULL); // RIGHT

    造成以上原因是因为lstrcpyn需要一个字W个C为参敎ͼ但是WriteFile却需要字节数作ؓ参数?br> 同样需要注意的是有时候需要写出数据的所有内宏V如果你仅仅只想写出数据的真实长度,你可能会认ؓ你应该这样做Q?/p>

    WriteFile(f, data, lstrlen(data), &bytesWritten, NULL); // WRONG

    但是在Unicode环境下,它不会正常工作。正的做法应该是这P

    WriteFile(f, data, lstrlen(data) * sizeof(TCHAR), &bytesWritten, NULL); // RIGHT

      因ؓWriteFile需要的是一个以字节为单位的长度。(可能有些Z?#8220;在非Unicode的环境下q行q行代码Q就意味着L在做一个多余的?操作Q这样不会降低程序的效率吗?”q种x是多余的Q你必须要了解编译器实际上做了什么,没有哪一个C或C++~译器会把这U无聊的?操作留在代码中。在Unicode环境下运行的时候,你也不必担心那个?操作会降低程序的效率Q记住,q只是一个左UM位的操作而已Q编译器也很乐意Z做这U替换。)
      使用_T宏ƈ不是意味着你已l创Z一个Unicode的程序,你只是创Z一个有Unicode意识的程序而已。如果你在默认的8-bit模式下编译你的程序的话,得到的将是一个普通的8-bit的应用程序(q里?-bit指的只是8位的字符~码Qƈ不是?位的计算机系l)Q当你在Unicode环境下编译你的程序时Q你才会得到一个Unicode的程序。记住,CString ?Unicode 环境下,里面包含的可都是16位的字符哦?br>
    3?b>

    4?b>

    或者这P

    CString graycat("Gray" + "Cat");

      事实上,~译器将抱怨上面的q些试。ؓ什么呢Q因为针对CString ?LPCTSTR数据cd的各U各Ll合Q?#8220; +” q算W? 被定义成一个重载操作符。而不是两?LPCTSTR 数据cdQ它是底层数据类型。你不能对基本数据(?int、char 或?char*Q类型重?C++ 的运符。你可以象下面这样做Q?/p>

    CString graycat = CString("Gray") + CString("Cat");

    或者这P

    CString graycat = CString("Gray") + "Cat";

    研究一番就会发玎ͼ“ +”L使用在至有一?CString 对象和一? LPCSTR 的场合?br>
    注意Q编写有 Unicode 意识的代码L一件好事,比如Q?/p>

    CString graycat = CString(_T("Gray")) + _T("Cat");

    q将使得你的代码可以直接UL?br>
    char* 转化?CString

      现在你有一?char* cd的数据,或者说一个字W串。怎么样创?CString 对象呢?q里有一些例子:

    char * p = "This is a test";

    或者象下面q样更具?Unicode 意识Q?/p>

    TCHAR * p = _T("This is a test")

    ?/p>

    LPTSTR p = _T("This is a test");

    你可以用下面Q意一U写法:

    CString s = "This is a test"; // 8-bit only
    CString s = _T("This is a test"); // Unicode-aware
    CString s("This is a test"); // 8-bit only
    CString s(_T("This is a test")); // Unicode-aware
    CString s = p;
    CString s(p);

      用这些方法可以轻村ְ帔R字符串或指针转换?CString。需要注意的是,字符的赋值L被拷贝到 CString 对象中去的,所以你可以象下面这h作:

    TCHAR * p = _T("Gray");
    CString s(p);
    p = _T("Cat");
    s += p;

    l果字符串肯定是“GrayCat”?br>
    CString c还有几个其它的构造函敎ͼ但是q里我们不考虑它,如果你有兴趣可以自己查看相关文档?br>
    事实上,CString cȝ构造函数比我展C的要复杂,比如Q?/p>

    CString s = "This is a test"; 

      q是很草率的~码Q但是实际上它在 Unicode 环境下能~译通过。它在运行时调用构造函数的 MultiByteToWideChar 操作?8 位字W串转换?16 位字W串。不怎样Q如?char * 指针是网l上传输?8 位数据,q种转换是很有用的?br>
    CString 转化?char* 之一Q?/b>强制cd转换?LPCTSTRQ?br>
      q是一U略微硬性的转换Q有?#8220;正确”的做法,Z在认识上q存在许多؜乱,正确的用方法有很多Q但错误的用方法可能与正确的用方法一样多?br>   我们首先要了?CString 是一U很Ҏ(gu)?C++ 对象Q它里面包含了三个|一个指向某个数据缓冲区的指针、一个是该缓冲中有效的字W记C及一个缓冲区长度? 有效字符数的大小可以是从0到该~冲最大长度值减1之间的Q何数Q因为字W串l尾有一个NULL字符Q。字W记数和~冲区长度被巧妙隐藏?br>   除非你做一些特D的操作Q否则你不可能知道给CString对象分配的缓冲区的长度。这P即你获得了?~冲的地址Q你也无法更改其中的内容Q不能截短字W串Q也 l对没有办法加长它的内容Q否则第一旉׃看到溢出?br>   LPCTSTR 操作W(或者更明确地说是 TCHAR * 操作W)?CString cM被重载了Q该操作W的定义是返回缓冲区的地址Q因此,如果你需要一个指?CString ? 字符串指针的话,可以q样做:

    CString s("GrayCat");
    LPCTSTR p = s;

      它可以正地q行。这是由C语言的强制类型{化规则实现的。当需要强制类型{化时QC++规测容许q种选择。比如,你可以将QQҎ(gu)Q定义ؓ某个复? Q有一Ҏ(gu)QҎ(gu)Q进行强制类型{换后只返回该复数的第一个QҎ(gu)Q也是其实部)。可以象下面q样Q?/p>

    Complex c(1.2f, 4.8f);
    float realpart = c;

    如果(float)操作W定义正的话,那么实部的的值应该是1.2?br>   q种强制转化适合所有这U情况,例如QQ何带?LPCTSTR cd参数的函数都会强制执行这U{换? 于是Q你可能有这样一个函敎ͼ也许在某个你买来的DLL中)Q?/p>

    BOOL DoSomethingCool(LPCTSTR s);

    你象下面q样调用它:

    CString file("c:\\myfiles\\coolstuff")
    BOOL result = DoSomethingCool(file);

      它能正确q行。因?DoSomethingCool 函数已经说明了需要一?LPCTSTR cd的参敎ͼ因此 LPCTSTR 被应用于该参敎ͼ?MFC 中就是返回的串地址?br>
    如果你要格式化字W串怎么办呢Q?/p>

    CString graycat("GrayCat");
    CString s;
    s.Format("Mew! I love %s", graycat);

      注意׃在可变参数列表中的|在函数说明中是以“...”表示的)q没有隐含一个强制类型{换操作符。你会得C么结果呢Q?br>   一个o人惊讶的l果Q我们得到的实际l果串是Q?/p>

    "Mew! I love GrayCat"?/pre>
          

      因ؓ MFC 的设计者们在设?CString 数据cd旉常小心, CString cd表达式求值后指向了字W串Q所以这里看不到M? Format ?sprintf 中的强制cd转换Q你仍然可以得到正确的行为。描q?CString 的附加数据实际上?CString 名义地址之后?br>   有一件事情你是不能做的,那就是修改字W串。比如,你可能会试?#8220;,”代替“.”Q不要做q样的,如果你在乎国际化问题Q你应该使用十进制{换的 National Language Support Ҏ(gu),Q,下面是个单的例子Q?/p>

    CString v("1.00"); // 货币金额Q两位小?
    LPCTSTR p = v;
    p[lstrlen(p) - 3] = '','';

      q时~译器会报错Q因Z赋g一个常量串。如果你做如下尝试,~译器也会错Q?/p>

    strcat(p, "each");

      因ؓ strcat 的第一个参数应该是 LPTSTR cd的数据,而你却给了一?LPCTSTR?br>
      不要试图钻这个错误消息的牛角,q只会你自己陷入麻烦!

      原因是缓冲有一个计敎ͼ它是不可存取的(它位?CString 地址之下的一个隐藏区域)Q如果你改变q个Ԍ~冲中的字符计数不会反映所做的修改。此外,如果字符串长度恰好是该字W串物理限制的长度(梢后q会讲到q个问题Q,那么扩展该字W串改写缓冲以外的M数据Q那是你无权q行写操作的内存Q不对吗Q)Q你会毁换坏不属于你的内存。这是应用程序真正的M处方?/p>

    CString转化成char* 之二Q?/b>使用 CString 对象?GetBuffer Ҏ(gu)Q?br>
      如果你需要修?CString 中的内容Q它有一个特D的Ҏ(gu)可以使用Q那是 GetBufferQ它的作用是q回一个可写的~冲指针? 如果你只是打修改字W或者截短字W串Q你完全可以q样做:

    CString s(_T("File.ext"));
    LPTSTR p = s.GetBuffer();
    LPTSTR dot = strchr(p, ''.''); // OK, should have used s.Find...
    if(p != NULL)
    *p = _T(''\0'');
    s.ReleaseBuffer();

      q是 GetBuffer 的第一U用法,也是最单的一U,不用l它传递参敎ͼ它用默认?0Q意思是Q?#8220;l我q个字符串的指针Q我保证不加长它”。当你调?ReleaseBuffer Ӟ字符串的实际长度会被重新计算Q然后存?CString 对象中?br>   必须一点,?GetBuffer ?ReleaseBuffer 之间q个范围Q一定不能用你要操作的q个~冲?CString 对象的Q何方法。因?ReleaseBuffer 被调用之前,?CString 对象的完整性得不到保障。研I以下代码:

    CString s(...);
    
    LPTSTR p = s.GetBuffer();
    
    //... q个指针 p 发生了很多事?
    
    int n = s.GetLength(); // 很糟D!!!!! 有可能给出错误的{案!!!
    
    s.TrimRight(); // 很糟!!!!! 不能保证能正常工?!!!
    
    s.ReleaseBuffer(); // 现在应该 OK
    
    int m = s.GetLength(); // q个l果可以保证是正的?
    
    s.TrimRight(); // 正常工作?/pre>
          

      假设你想增加字符串的长度Q你首先要知道这个字W串可能会有多长Q好比是声明字符串数l的时候用Q?/p>

    char buffer[1024];

    表示 1024 个字W空间以让你做M惛_得事情。在 CString 中与之意义相{的表示法:

    LPTSTR p = s.GetBuffer(1024);

      调用q个函数后,你不仅获得了字符串缓冲区的指针,而且同时q获得了长度臛_?1024 个字W的I间Q注意,我说的是“字符”Q而不?#8220;字节”Q因?CString 是以隐含方式感知 Unicode 的)?br>   同时Q还应该注意的是Q如果你有一个常量串指针Q这个串本n的D存储在只d存中Q如果试囑֭储它Q即使你已经调用?GetBuffer Qƈ获得一个只d存的指针Q存入操作会p|Qƈ报告存取错误。我没有?CString 上证明这一点,但我看到q大把的 C E序员经常犯q个错误?br>   C E序员有一个通病是分配一个固定长度的~冲Q对它进?sprintf 操作Q然后将它赋值给一?CStringQ?/p>

    char buffer[256];
    sprintf(buffer, "%......", args, ...); // ... 部分省略许多l节
    CString s = buffer;

    虽然更好的Ş式可以这么做Q?/p>

    CString s;
    s.Format(_T("%...."), args, ...);

    如果你的字符串长度万一过 256 个字W的时候,不会破坏堆栈?br>
      另外一个常见的错误是:既然固定大小的内存不工作Q那么就采用动态分配字节,q种做法弊端更大Q?/p>

    int len = lstrlen(parm1) + 13  lstrlen(parm2) + 10 + 100;
    
    char * buffer = new char[len];
    
    sprintf(buffer, "%s is equal to %s, valid data", parm1, parm2);
    
    CString s = buffer;
    
    ......
    
    delete [] buffer;

    它可以能被简单地写成Q?/p>

    CString s;
    
    s.Format(_T("%s is equal to %s, valid data"), parm1, parm2);

      需要注?sprintf 例子都不?Unicode qA的,管你可以?tsprintf 以及?_T() 来包围格式化字符Ԍ但是基本 思\仍然是在走弯路,q这样很Ҏ(gu)出错?br>
    CString to char * 之三Q?/b>和控件的接口Q?br>
      我们l常需要把一?CString 的g递给一个控Ӟ比如QCTreeCtrl。MFC为我们提供了很多便利来重载这个操作,但是 在大多数情况下,你?#8220;原始”形式的更斎ͼ因此需要将墨某个串指针存储?TVINSERTITEMSTRUCT l构?TVITEM 成员中。如下:

    TVINSERTITEMSTRUCT tvi;
    CString s;
    // ... 为s赋一些倹{?
    tvi.item.pszText = s; // Compiler yells at you here
    // ... 填写tvi的其他域
    HTREEITEM ti = c_MyTree.InsertItem(&tvi);

      Z么编译器会报错呢Q明明看h很完的用法啊!但是事实上如果你看看 TVITEM l构的定义你׃明白Q在 TVITEM l构?pszText 成员的声明如下:

    LPTSTR pszText;
    int cchTextMax;

      因此Q赋g是赋l一?LPCTSTR cd的变量,而且~译器无法知道如何将赋D句右边强制{换成 LPCTSTR。好吧,你说Q那我就Ҏ(gu)q样Q?/p>

    tvi.item.pszText = (LPCTSTR)s; //~译器依然会报错?/pre>
          

      ~译器之所以依然报错是因ؓ你试图把一?LPCTSTR cd的变量赋值给一?LPTSTR cd的变量,q种操作在C或C++中是被禁止的。你不能用这U方? 来滥用常量指针与非常量指针概念,否则Q会Cؕ~译器的优化机制Q之不知如何优化你的程序。比如,如果你这么做Q?/p>

    const int i = ...;
    //... do lots of stuff
    ... = a[i]; // usage 1
    // ... lots more stuff
    ... = a[i]; // usage 2

      那么Q编译器会以为既?i ?const Q所?usage1和usage2的值是相同的,q且它甚臌事先计算?usage1 处的 a[i] 的地址Q然后保留着在后面的 usage2 处用,而不是重新计。如果你按如下方式写的话Q?/p>

    const int i = ...;
    int * p = &i;
    //... do lots of stuff
    ... = a[i]; // usage 1
    // ... lots more stuff
    (*p)++; // mess over compiler''s assumption
    // ... and other stuff
    ... = a[i]; // usage 2

      ~译器将认ؓ i 是常量,从?a[i] 的位|也是常量,q样间接地破坏了先前的假设。因此,你的E序会?debug ~译模式Q没有优化)?release ~译模式Q完全优化)中反映出不同的行为,q种情况可不好,所以当你试图把指向 i 的指针赋值给一? 可修改的引用Ӟ会被~译器诊断ؓq是一U伪造。这是Z么(LPCTSTRQ强制类型{化不起作用的原因?br>   Z么不把该成员声明?LPCTSTR cd呢?因ؓq个l构被用于读写控件。当你向控g写数据时Q文本指针实际上被当?LPCTSTRQ而当你从控gL? Ӟ你必L一个可写的字符丌Ӏ这个结构无法区分它是用来读q是用来写?br>
    因此Q你会常常在我的代码中看到如下的用法Q?/p>

    tvi.item.pszText = (LPTSTR)(LPCTSTR)s;

      它把 CString 强制cd转化?LPCTSTRQ也是说先获得改字W串的地址Q然后再强制cd转化?LPTSTRQ以便可以对之进行赋值操作? 注意q只有在使用 Set ?Insert 之类的方法才有效Q如果你试图获取数据Q则不能q么做?br>   如果你打获取存储在控g中的数据Q则Ҏ(gu)E有不同Q例如,Ҏ(gu)?CTreeCtrl 使用 GetItem Ҏ(gu)Q我惌取项目的文本。我知道q些 文本的长度不会超q?MY_LIMITQ因此我可以q样写:

    TVITEM tvi;
    // ... assorted initialization of other fields of tvi
    tvi.pszText = s.GetBuffer(MY_LIMIT);
    tvi.cchTextMax = MY_LIMIT;
    c_MyTree.GetItem(&tvi);
    s.ReleaseBuffer();

      可以看出来,其实上面的代码对所有类型的 Set Ҏ(gu)都适用Q但是ƈ不需要这么做Q因为所有的c?Set Ҏ(gu)Q包? InsertҎ(gu)Q不会改变字W串的内宏V但是当你需要写 CString 对象Ӟ必须保证~冲是可写的Q这正是 GetBuffer 所做的事情。再ơ强调: 一旦做了一?GetBuffer 调用Q那么在调用 ReleaseBuffer 之前不要对这?CString 对象做Q何操作?br>
    5?b> 6?b>

      对于单个?BSTR 串来_q种用法可以工作得很好,q是因ؓ CString 有一个特D的构造函CLPCWSTRQBSTR正是q种cdQ? 为参敎ͼq将它{化成 ANSI cd。专门检查是必须的,因ؓ BSTR 可能为空|?CString 的构造函数对?NULL 值情况考虑的不是很周到Q(感谢 Brian Ross 指出q一?Q。这U用法也只能处理包含 NUL l结字符的单字符Ԍ如果要{化含有多?NULL 字符 Ԍ你得额外做一些工作才行。在 CString 中内嵌的 NULL 字符通常表现不尽如h意,应该量避免?br>   Ҏ(gu) C/C++ 规则Q如果你有一?LPWSTRQ那么它别无选择Q只能和 LPCWSTR 参数匚w?br>
    ?Unicode 模式下,它的构造函数是Q?/p>

    CString::CString(LPCTSTR);

    正如上面所表示的,?ANSI 模式下,它有一个特D的构造函敎ͼ

    CString::CString(LPCWSTR); 

      它会调用一个内部的函数?Unicode 字符串{换成 ANSI 字符丌Ӏ(在Unicode模式下,有一个专门的构造函敎ͼ该函数有一个参数是LPCSTRcd——一??ANSI 字符? 指针Q该函数它加宽?Unicode 的字W串Q)再次Q一定要?BSTR 的值是否ؓ NULL?br>   另外q有一个问题,正如上文提到的:BSTRs可以含有多个内嵌的NULL字符Q但?CString 的构造函数只能处理某个串中单?NULL 字符? 也就是说Q如果串中含有嵌入的 NUL字节QCString 会计算出错误的串长度。你必须自己处理它。如果你看看 strcore.cpp 中的构造函敎ͼ你会发现 它们都调用了lstrlenQ也是计算字符串的长度?br>   注意?Unicode ?ANSI 的{换用带专门参数?::WideCharToMultiByteQ如果你不想使用q种默认的{换方式,则必ȝ写自q转化代码?br>   如果你在 UNICODE 模式下编译代码,你可以简单地写成Q?br>

    CString convert(BSTR b)
    {
        if(b == NULL)
            return CString(_T(""));
        CString s(b); // in UNICODE mode
        return s;
    }
    
      如果?ANSI 模式Q则需要更复杂的过E来转换。注意这个代码用与 ::WideCharToMultiByte 相同的参数倹{所以你 只能在想要改变这些参数进行{换时使用该技术。例如,指定不同的默认字W,不同的标志集{?
    CString convert(BSTR b)
    {
        CString s;
        if(b == NULL)
           return s; // empty for NULL BSTR
    #ifdef UNICODE
        s = b;
    #else
        LPSTR p = s.GetBuffer(SysStringLen(b) + 1); 
        ::WideCharToMultiByte(CP_ACP,            // ANSI Code Page
                              0,                 // no flags
                              b,                 // source widechar string
                              -1,                // assume NUL-terminated
                              p,                 // target buffer
                              SysStringLen(b)+1, // target buffer length
                              NULL,              // use system default char
                              NULL);             // don''t care if default used
        s.ReleaseBuffer();
    #endif
        return s;
    }
    
      我ƈ不担心如?BSTR 包含没有映射?8 位字W集?Unicode 字符时会发生什么,因ؓ我指定了::WideCharToMultiByte 的最后两个参Cؓ NULL。这是你可能需要改变的地方?

    7?b>
    lVal); return s; case VT_I4 | VT_BYREF: s.Format(_T("%d"), *va->plVal); case VT_R8: s.Format(_T("%f"), va->dblVal); return s; ... 剩下的类型{换由读者自己完? default: ASSERT(FALSE); // unknown VARIANT type (this ASSERT is optional) return CString(""); } /* vt */ }
    8?b>载入字符串表资源


      如果你想创徏一个容易进行语a版本UL的应用程序,你就不能在你的源代码中直接包含本土语a字符? Q下面这些例子我用的语言都是pQ因为我的本土语是英语)Q比如下面这U写法就很糟Q?pre>CString s = "There is an error";

      你应该把你所有特定语a的字W串单独摆放Q调试信息、在发布版本中不出现的信息除外)。这意味着向下面这样写比较好:

    s.Format(_T("%d - %s"), code, text);

      在你的程序中Q文字字W串不是语言敏感的。不怎样Q你必须很小心,不要使用下面q样的串Q?/p>

    // fmt is "Error in %s file %s"
    // readorwrite is "reading" or "writing"
    s.Format(fmt, readorwrite, filename); 

      q是我的切n体会。在我的W一个国际化的应用程序中我犯了这个错误,管我懂徯Q知道在徯的语法中动词攑֜句子的最后面Q我们的德国斚w的发行hq是苦苦的抱怨他们不得不提取那些不可思议的d语错误提CZ息然后重新格式化以让它们能正常工作。比较好的办法(也是我现在用的办法Q是使用两个字符Ԍ一个用 于读Q一个用于写Q在使用时加载合适的版本Q得它们对字符串参数是非敏感的。也是说加载整个格式,而不是加载串“reading”Q?#8220;writing”Q?/p>

    // fmt is "Error in reading file %s"
    // "Error in writing file %s"
    s.Format(fmt, filename);

      一定要注意Q如果你有好几个地方需要替换,你一定要保证替换后句子的l构不会出现问题Q比如在p中,可以是主?宾语Q主?谓语Q动?宾语的结构等{?br>   在这里,我们q不讨论 FormatMessageQ其实它?sprintf/Format q要有优势,但是不太Ҏ(gu)和CString l合使用。解册U问题的办法是我们按照参数出现在参数表中的位置l参数取名字Q这样在你输出的时候就不会把他们的位置排错了?br>   接下来我们讨论我们这些独立的字符串放在什么地斏V我们可以把字符串的值放入资源文件中的一个称?STRINGTABLE 的段中。过E如下:首先使用 Visual Studio 的资源编辑器创徏一个字W串Q然后给每一个字W串取一个IDQ一般我们给它取名字都以 IDS_开头。所以如果你有一个信息,你可以创Z个字W串资源然后取名?IDS_READING_FILEQ另外一个就取名?IDS_WRITING_FILE。它们以下面的Ş式出现在你的 .rc 文g中:

    STRINGTABLE
    IDS_READING_FILE "Reading file %s"
    IDS_WRITING_FILE "Writing file %s"
    END

    注意Q?/b>q些资源都以 Unicode 的格式保存,不管你是在什么环境下~译。他们在Win9xpȝ上也是以Unicode 的Ş式存在,虽然 Win9x 不能真正处理 Unicode?br> 然后你可以这样用这些资源:
    // 在用资源串表之前,E序是这样写的:

       CString fmt;
          if(...)
            fmt = "Reading file %s";
         else
           fmt = "Writing file %s";
      ...
        // much later
      CString s;
      s.Format(fmt, filename); 
    
    // 使用资源串表之后Q程序这样写Q?
        CString fmt;
            if(...)
               fmt.LoadString(IDS_READING_FILE);
            else
               fmt.LoadString(DS_WRITING_FILE);
        ...
          // much later
        CString s;
        s.Format(fmt, filename);
    
      现在Q你的代码可以移植到M语言中去。LoadString Ҏ(gu)需要一个字W串资源?ID 作ؓ参数Q然后它?STRINGTABLE 中取出它对应的字W串Q赋值给 CString 对象? CString 对象的构造函数还有一个更加聪明的特征可以?STRINGTABLE 的用。这个用法在 CString::CString 的文档中没有指出Q但是在 构造函数的CZE序中用了。(Z么这个特性没有成为正式文档的一部分Q而是攑֜了一个例子中Q我C得了Q)——?b>译者注
    Q从q句话看Q作者可能是CString的设计者。其实前面还有一句类似的话。说他没有对使用GetBuffer(0)获得的指针指向的地址是否可读做有效性检? 】。这个特征就是:如果你将一个字W串资源的ID强制cd转换?LPCTSTRQ将会隐含调?LoadString。因此,下面两个构造字W串的例子具有相同的效果Q而且?ASSERT 在debug模式下不会被触发Q?pre>CString s; s.LoadString(IDS_WHATEVER); CString t( (LPCTSTR)IDS_WHATEVER ); ASSERT(s == t);//不会被触发,说明s和t是相同的?/pre>

      现在Q你可能会想Q这怎么可能工作呢?我们怎么能把 STRINGTABLE ID 转化成一个指针呢Q很单:所有的字符?ID 都在1~65535q个范围内,也就是说Q它所有的高位都是0Q而我们在E序中所使用的指针是不可能小?5535的,因ؓE序的低 64K 内存永远也不可能存在的,如果你试图访?x00000000?x0000FFFF之间的内存,会引发一个内存越界错误。所以说1~65535的g可能是一个内存地址Q所以我们可以用q些值来作ؓ字符串资源的ID?br>   我們֐于?MAKEINTRESOURCE 宏显式地做这U{换。我认ؓq样可以让代码更加易于阅诅R这是个只适合?MFC 中用的标准宏。你要记住,大多数的Ҏ(gu)卛_以接受一?UINT 型的参数Q也可以接受一?LPCTSTR 型的参数Q这是依?C++ 的重载功能做到的。C++重蝲函数带来? 弊端是造成所有的强制cd转化都需要显C声明。同P你也可以l很多种l构只传递一个资源名?/p>

    CString s;
    s.LoadString(IDS_WHATEVER);
    CString t( MAKEINTRESOURCE(IDS_WHATEVER));
    ASSERT(s == t);

      告诉你吧Q我不仅只是在这里鼓吹,事实上我也是q么做的。在我的代码中,你几乎不可能扑ֈ一个字W串Q当Ӟ那些只是偶然在调试中出现的或者和语言无关的字W串除外?br>
    9?b>

    char* szName = GetName().GetBuffer(20);
    RegSetValueEx(hKey, "Name", 0, REG_SZ, 
                 (CONST BYTE *) szName,
                 strlen (szName + 1));

    q个 Name 字符串的长度于 20Q所以我不认为是 GetBuffer 的参数的问题?br>
    真让人困惑,请帮帮我?br>
    亲爱?FrustratedQ?br>
    你犯了一个相当微妙的错误Q聪明反被聪明误Q正的代码应该象下面这P

    CString Name = GetName();
    RegSetValueEx(hKey, _T("Name"), 0, REG_SZ, 
                        (CONST BYTE *) (LPCTSTR)Name,
                        (Name.GetLength() + 1) * sizeof(TCHAR));
    
      Z么我写的代码能行而你写的有问题呢?主要是因为当你调?GetName 时返回的 CString 对象是一个时对象。参见:《C++ Reference manual?#167;12.2
      在一些环境中Q编译器有必要创Z个时对象,q样引入临时对象是依赖于实现的。如果编译器引入的这个时对象所属的cL构造函数的话,~译器要保q个cȝ构造函数被调用。同LQ如果这个类声明有析构函数的话,也要保证q个临时对象的析构函数被调用?br>   ~译器必M证这个时对象被销毁了。被销毁的切地点依赖于实?....q个析构函数必须在退出创临时对象的范围之前被调用?br>   大部分的~译器是q样设计的:在时对象被创徏的代码的下一个执行步骤处隐含调用q个临时对象的析构函敎ͼ实现hQ一般都是在下一个分号处。因此,q个 CString 对象?GetBuffer 调用之后p析构了(Z提一句,你没有理q GetBuffer 函数传递一个参敎ͼ而且没有使用ReleaseBuffer 也是不对的)。所?GetBuffer 本来q回的是指向q个临时对象中字W串的地址的指针,但是当这个时对象被析构后,q块内存p释放了。然?MFC 的调试内存分配器会重Cؓq块内存全部填上 0xDDQ显C出来刚好就?#8220;Ý”W号。在q个时候你向注册表中写数据Q字W串的内容当然全被破坏了?br>   我们不应该立xq个临时对象转化?char* cdQ应该先把它保存C?CString 对象中,q意味着把时对象复制了一份,所以当临时?CString 对象被析构了之后Q这?CString 对象中的g然保存着。这个时候再向注册表中写数据没有问题了?br>   此外Q我的代码是h Unicode 意识的。那个操作注册表的函数需要一个字节大,使用lstrlen(Name+1) 得到的实际结果对?Unicode 字符来说?ANSI 字符要小一半,而且它也不能从这个字W串的第二个字符起开始计,也许你的本意?lstrlen(Name) + 1QOKQ我承认Q我也犯了同L错误Q)。不论如何,?Unicode 模式下,所有的字符都是2个字节大,我们需要处理这个问题。微软的文档令h惊讶地对此保持缄默:REG_SZ 的值究竟是以字节计还是以字符计算呢?我们假设它指的是以字节ؓ单位计算Q你需要对你的代码做一些修Ҏ(gu)计算q个字符串所含有的字节大?br>
    10?b>

    比v下面的代码来Q效率要低多了:

    char s[1024];
    lstrcpy(s, SomeString1);
    lstrcat(s, SomeString2);
    lstrcat(s, SomeString 3);
    lstrcat(s, ",");
    lstrcat(s, SomeString4);

      MQ你可能会想Q首先,它ؓ SomeCString1 分配一块内存,然后?SomeCString1 复制到里面,然后发现它要做一个连接,则重新分配一块新的够大的内存,大到能够放下当前的字W串加上SomeCString2Q把内容复制到这块内? Q然后把 SomeCString2 q接到后面,然后释放W一块内存,q把指针重新指向新内存。然后ؓ每个字符串重复这个过E。把q?4 个字W串q接h效率多低啊。事实上Q在很多情况下根本就不需要复制源字符Ԍ?+= 操作W左边的字符Ԍ?br>   ?VC++6.0 中,Release 模式下,所有的 CString 中的~存都是按预定义量子分配的。所谓量子,即确定ؓ 64?28?56 或?512 字节。这意味着除非字符串非帔RQ连接字W串的操作实际上是 strcat l过优化后的版本Q因为它知道本地的字W串应该在什么地方结束,所以不需要寻扑֭W串的结;只需要把内存中的数据拯到指定的地方卛_Q加上重新计字W串的长度。所以它的执行效率和U?C 的代码是一LQ但是它更容易写、更Ҏ(gu)l护和更Ҏ(gu)理解?br>   如果你还是不能确定究竟发生了怎样的过E,L?CString 的源代码Qstrcore.cppQ在?vc98的安装目录的 mfc\src 子目录中。看?ConcatInPlace Ҏ(gu)Q它被在所有的 += 操作W中调用?br>
    啊哈Q难?CString 真的q么"高效"吗?比如Q如果我创徏

    CString cat("Mew!");

      然后我ƈ不是得到了一个高效的、精?个字节大的~冲区(4个字W加一个结束字W)Q系l将l我分配64个字节,而其?9个字节都被浪费了?br>   如果你也是这么想的话Q那么就请准备好接受再教育吧。可能在某个地方某个人给你讲q尽量用少的空间是件好事情。不错,q种说法的确正确Q但是他忽略了事实中一个很重要的方面?br>   如果你编写的是运行在16K EPROMs下的嵌入式程序的话,你有理由量用空_在这U环境下Q它能你的E序更健壮。但是在 500MHz, 256MB的机器上?Windows E序Q如果你q是q么做,它只会比你认为的“低效”的代码运行得更糟?br>   举例来说。字W串的大被认ؓ是媄响效率的首要因素Q字符串尽可能可以提高效率,反之则降低效率,q是大家一贯的x。但是这U想法是不对的,_的内存分配的后果要在E序q行了好几个时后才能体现得出来Q那ӞE序的堆中将充满片的内存,它们太小以至于不能用来做M事,但是他们增加了你E序的内存用量,增加了内存页面交换的ơ数Q当面交换的次数增加到pȝ能够忍受的上限,pȝ则会Z的程序分配更多的面Q直C的程序占用了所有的可用内存。由此可见,虽然内存片是决定效率的ơ要因素Q但正是q些因素实际控制了系l的行ؓQ最l,它损害了pȝ的可靠性,q是令h无法接受的?br>   CQ在 debug 模式下,内存往往是精分配的Q这是ؓ了更好的排错?br>   假设你的应用E序通常需要连l工作好几个月。比如,我常打开 VC++QWordQPowerPointQFrontpageQOutlook ExpressQForté AgentQInternet Explorer和其它的一些程序,而且通常不关闭它们。我曄夜以l日地连l用 PowerPoint 工作了好几天Q反之,如果你不q怸得不使用?Adobe FrameMaker q样的程序的话,你将会体会到可靠性的重要Q这个程序机会每天都要崩?~6ơ,每次都是因ؓ用完了所有的I间q填满我所有的交换面Q。所以精内存分配是不可取的Q它会危及到pȝ的可靠性,q引起应用程序崩溃?br>   按量子的倍数为字W串分配内存Q内存分配器可以回收用q的内存块,通常q些回收的内存块马上可以被其它?CString 对象重新用到Q这样就可以保证片最。分配器的功能加ZQ应用程序用到的内存p可能保持最,q样的程序就可以q行几个星期或几个月而不出现问题?br>   题外话:很多q以前,我们?CMU 写一个交互式pȝ的时候,一些对内存分配器的研究昄出它往往产生很多内存片。Jim MitchellQ现在他?Sun Microsystems 工作Q那时侯他创造了一U内存分配器Q它保留了一个内存分配状늚q行时统计表Q这U技术和当时的主分配器所用的技术都不同Q且较ؓ领先。当一个内存块需要被分割得比某一个值小的话Q他q不分割它,因此可以避免产生太多到什么事都干不了的内存碎片。事实上他在内存分配器中使用了一个Q动指针,他认为:与其让指令做长时间的存取内存操作Q还不如单的忽略那些太小的内存块而只做一些Q动指针的操作。(His observation was that the long-term saving in instructions by not having to ignore unusable small storage chunks far and away exceeded the additional cost of doing a few floating point operations on an allocation operation.Q他是对的?br>   永远不要认ؓ所谓的“最优化”是徏立在每一行代码都高速且节省内存的基上的Q事实上Q高速且节省内存应该是在一个应用程序的整体水^上考虑的。在软g的整体水q上Q只使用最内存的字符串分配策略可能是最p糕的一U方法?br>   如果你认Z化是你在每一行代码上做的那些努力的话Q你应该想一惻I在每一行代码中做的优化很少能真正v作用。你可以看我的另一关于优化问题的文章《Your Worst Enemy for some thought-provoking ideas》?br>   CQ?= q算W只是一U特例,如果你写成下面这P

    CString s = SomeCString1 + SomeCString2 + SomeCString3 + "," + SomeCString4;

    则每一?+ 的应用会造成一个新的字W串被创建和一ơ复制操作?br>
    ȝ

      以上是?CString 的一些技巧。我每天写程序的时候都会用到这些。CString q不是一U很难用的c,但是 MFC 没有很明昄指出q些特征Q需要你自己L索、去发现?br>

    ]]>关于char, wchar_t, TCHAR, _T(),L,?_T、TEXT,_TEXT、Lhttp://www.shnenglu.com/brucejini/articles/98682.html路h?/dc:creator>路h?/author>Thu, 15 Oct 2009 06:16:00 GMThttp://www.shnenglu.com/brucejini/articles/98682.htmlhttp://www.shnenglu.com/brucejini/comments/98682.htmlhttp://www.shnenglu.com/brucejini/articles/98682.html#Feedback0http://www.shnenglu.com/brucejini/comments/commentRss/98682.htmlhttp://www.shnenglu.com/brucejini/services/trackbacks/98682.html 

    char :单字节变量类型,最多表C?56个字W,

    wchar_t :宽字节变量类型,用于表示Unicode字符Q?/p>

    它实际定义在<string.h>里:typedef unsigned short wchar_t?/p>

    Z让编译器识别Unicode字符Ԍ必须以在前面加一?#8220;L”,定义宽字节类型方法如下:

        wchar_t c = `A' ;
    wchar_t * p = L"Hello!" ;
    wchar_t a[] = L"Hello!" ;

    其中Q宽字节cd每个变量占用2个字节,故上q数la的sizeof(a) = 14

    TCHAR / _T( ) :
    如果在程序中既包括ANSI又包括Unicode~码Q需要包括头文gtchar.h。TCHAR是定义在该头文g中的宏,它视你是否定义了_UNICODE宏而定义成Q?
    定义了_UNICODEQ?nbsp;   typedef wchar_t TCHAR ;
    没有定义_UNICODEQ?typedef char TCHAR ;

    #ifdef UNICODE
    typedef char TCHAR;
    #else
    typede wchar_t TCHAR;
    #endif
    _T( )也是定义在该头文件中的宏Q视是否定义了_UNICODE宏而定义成Q?
    定义了_UNICODEQ?nbsp;   #define _T(x) L##x
    没有定义_UNICODEQ?#define _T(x) x
    注意Q如果在E序中用了TCHARQ那么就不应该用ANSI的strXXX函数或者Unicode的wcsXXX函数了,而必M用tchar.h中定义的_tcsXXX函数?/p>

    以strcpy函数Z子,ȝ一下:
     

    //如果你想使用ANSI字符Ԍ那么请用这一套写法: 
    char szString[100]; 
    strcpy(szString,
    "test"); 
    //如果你想使用Unicode字符Ԍ那么请用这一套: 
    wchar_t szString[100]; 
    wcscpy(szString,L
    "test"); 
    //如果你想通过定义_UNICODE宏,而编译ANSI或者Unicode字符串代码: 
    TCHAR szString[100]; 
    _tcscpy(szString,_TEXT(
    "test"));

     

    CSDN:superarhow_ 不要再用TCHAR和_T了!他分析了原因后ȝQ如 果?zhn)正开始一个新的项目,h论如何也要顶住压力,直接使用UNICODE~码Q切讎ͼ(zhn)只需要对(zhn)的l员q行10分钟的培训,Cstrcpy?wcscpyQsprintf用swprintf代替Q常数前加LQ就可以了!它不会花(zhn)很多时间的Q带l?zhn)的是E_和安全!怿Ӟ没错的!Q?/p>

    一?在字W串前加一个L作用:
       ?nbsp; L"我的字符?    表示ANSI字符串{换成unicode的字W串Q就是每个字W占用两个字节?
      strlen("asd")   =   3;  
      strlen(L"asd")   =   6;
      二?nbsp; _T宏可以把一个引号引h的字W串Q根据你的环境设|,使得~译器会Ҏ(gu)~译目标环境选择合适的QUnicodeq是ANSIQ字W处理方?
       如果你定义了UNICODEQ那么_T宏会把字W串前面加一个L。这?_T("ABCD") 相当?L"ABCD" Q这是宽字符丌Ӏ?
       如果没有定义Q那么_T宏不会在字符串前面加那个LQ_T("ABCD") q价于 "ABCD"
    三、TEXT,_TEXT 和_T 一L
    如下面三语句Q?nbsp; 
      TCHAR   szStr1[]   =   TEXT("str1");  
      char   szStr2[]   =   "str2";  
      WCHAR   szStr3[]   =   L("str3");  
      那么W一句话在定义了UNICODE时会解释为第三句话,没有定义时就{于W二句话?nbsp; 
      但二句话无论是否定义了UNICODE都是生成一个ANSI字符Ԍ而第三句话L生成UNICODE字符丌Ӏ?nbsp; 
      ZE序的可UL性,都用W一U表C方法?nbsp; 
      但在某些情况下,某个字符必须为ANSI或UNICODEQ那q后两U方法?/p>

    ]]>
    þһ| þþþ޾Ʒһ| ޹Ʒþþþ | þþƷŷպ| þþƷ| þĻר| ˾þô߽avһ| ƷþþþjkƷ| Ʒþþþþù| þɫۺҹž| þù׾Ʒǿ| ŷպþAV| þ99þ99Ʒӿ| þĻȫ| ޹˾þþƷ99| þþþAVƬ| þ| ҹƷþ2021| ޾Ʒþþþþ| Ʒþþþþþþ | þþѾƷre6| ˳þõӰվ| TOKYOۺϾþþƷ| 2021ƷþþƷ| þþƷ99þ㽶| һһþþƷۺ| þþþһƷɫav | ˾þں2019| 18պҹþó| þþƷѲ| ޹Ʒþ| þþƷ| Ʒþþþþ| 7777Ʒþþô߽| þAV뾫Ʒ| ˳ɾƷþþþ| þ޾Ʒa| ޹Ʒþ| þþþƷþþþþ| ƷëٸAVѾþ | AVɫۺϾþAVɫۺ |