青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

笑看風(fēng)云淡

寵辱不驚,看庭前花開花落;去留無意,望天空云卷云舒
posts - 96, comments - 48, trackbacks - 0, articles - 0
  C++博客 :: 首頁 :: 新隨筆 ::  :: 聚合  :: 管理
先來看看CString的使用:

先定義幾個(gè)以后會(huì)用到的變量:

CString str1, str2, str3;

概括說明:

    MFC對(duì)CString類的封裝可能的確不如std::string完善,但是也的確不錯(cuò),功能也足夠強(qiáng)大,使用上還很體貼。其基本特征為:

    CString類沒有基類。

    CString類和LPCTSTR的關(guān)系:MSDN上說“CString objects follow "value semantics." Think of a CString object as an actual string, not as a pointer to a string.”也就是說用的時(shí)候除了考慮使用它的成員函數(shù)的方式,就把它當(dāng)作普通的c-style字符串來使用就行了。你可以在構(gòu)造函數(shù)中使用LPCTSTR:

        CString str("Hello World!");

可以:

       str1 = str2;                或者   str1 = “Hello”;

也可以:

       str3 = str1 + str2;     或者   str3 = str1 + “Hello”;

當(dāng)然也可以:

       str1 += str2;              或者       str1 += “Hello”;

實(shí)際上下列的這些操作符都可以用在CString對(duì)象之間或者CString和LPCTSTR對(duì)象之間:

       ==、!=、<、>、<=、>=

自然,將CString對(duì)象強(qiáng)制轉(zhuǎn)換到LPCTSTR類型也就應(yīng)該在情理之中:

       LPCTSTR string = (LPCTSTR) str1;

    CString支持UNICODE和多字節(jié)字符集(MBCS)。因?yàn)槠浔旧硎腔赥CHAR的——當(dāng)然你不要忘了定義編碼方式,如:#define _UNICODE。

    CString支持引用計(jì)數(shù)??梢酝ㄟ^其成員函數(shù)LockBuffe/和UnLockBuffer來禁用/啟用引用計(jì)數(shù)。


對(duì)于CString類的成員函數(shù)的定義、說明、返回值等形式在此并不贅述,如有此疑問請(qǐng)參閱:http://msdn.microsoft.com/library/en-us/vcmfc98/html/_mfc_cstring_class_members.asp中的相關(guān)鏈接。

常用函數(shù)和范例:

改變大小寫:

CString::MakeUpper和CString::MakeLower兩個(gè)成員函數(shù)(不帶參數(shù))能使整個(gè)字符串變成大/小寫字母。

例:       str1 = “hello”;

               str1.MakeUpper();

               afxDump << str1;         // 輸出結(jié)果是”HELLO”;

反轉(zhuǎn):void CString::MakeReverse();

從.rc文件讀入字符串:

CString::LoadString函數(shù)把傳入的字符串資源ID對(duì)應(yīng)的字符串讀入到CString對(duì)象中。如果成功就返回非零值。

       BOOL bResult = LoadString(IDS_FILENOTFOUND);

子串操作

→去掉字符串左邊空格:str1.TrimLeft();

→去掉字符串右邊空格:str1.TrimRight();

→獲得指定位置字符:char a = str1.GetAt(3); 相應(yīng)的有CString::SetAt函數(shù),修改指定位置字符。

→刪除字符串中所有指定字符:

       str1 = “Hello test”;

       str1.Remove(‘t’);

       afxDump << str1;         //輸出”Hello es”;

→刪除指定位置指定長(zhǎng)度的子串:

       str1 = “Hello test”;

       str1.Delete(3, 2);           //第一個(gè)參數(shù)為index(從零開始)

                                          //第二個(gè)參數(shù)是長(zhǎng)度

       afxDump << str1;         //輸出”Hel test”;

→清空對(duì)象的內(nèi)容:

void CString::Empty();

→查找子串:

※CString::Find函數(shù)有四個(gè)重載,可以進(jìn)行字符和字串的搜索,同時(shí)還可以指定搜索的起始位置,并返回第一次查找到的index。

int Find( TCHAR ch ) const;

int Find( LPCTSTR lpszSub ) const;

int Find( TCHAR ch, int nStart ) const;

int Find( LPCTSTR pstr, int nStart ) const;

※CString::ReverseFind是返回字符串中最后一個(gè)匹配字符的index,與Find函數(shù)查找方向正好相反,可惜只有一種重載:

int ReverseFind( TCHAR ch ) const;

※CString::FindOneof查找的是第一個(gè)與指定字符串中任意一個(gè)匹配字符的index。(好像有點(diǎn)繞口,看看例子就明白了)

       str1 = “Hello test”;

       int j = str1.Find(“el”);

       afxDump << “j=” << j << “\n”;

       int k = str1.Find(‘e’, 3);

       afxDump << “k=” << k << “\n”;

       int l = str1.ReverseFind(‘t’);

       afxDump << “l=” << l << “\n”;

       int m = str1.ReverseFind(‘t’);

       afxDump << “m=” << m << “\n”;

       int n = str1. FindOneOf(“stuv”);

       afxDump << “n=” << n << “\n”;

輸出結(jié)果:

       j=1

       k=7

       l=9

       m=9

       n=6

→字串截?cái)啵篊String::Left、CString::Right函數(shù)都只帶一個(gè)參數(shù),并且都返回一個(gè)CString對(duì)象,作用是截取左/右邊指定長(zhǎng)度的子串。CString::Mid函數(shù)第一個(gè)參數(shù)指定位置,第二個(gè)參數(shù)指定長(zhǎng)度。這幾個(gè)都是常用的函數(shù),就不寫例子了

→獲得Buffer

經(jīng)常有人問到CString對(duì)象和char *的轉(zhuǎn)換問題,除了前面說到的強(qiáng)制轉(zhuǎn)化,就是用這個(gè)了

LPTSTR GetBufferSetLength( int nNewLength );使用返回的指針可以直接修改CString對(duì)象的內(nèi)容,不過有兩點(diǎn)要注意,一是如果指定長(zhǎng)度比原CString長(zhǎng)度短(截?cái)啵┱?qǐng)記得在后面補(bǔ)’\0’,二是在調(diào)用CString對(duì)象的任何其它成員函數(shù)前請(qǐng)一定記得ReleaseBuffer,也許不用似乎并沒有出錯(cuò),但是說不定就是大隱患的根源。

→CString::SpanExcluding函數(shù)

以前回答過一個(gè)把CString對(duì)象分離子串的問題,現(xiàn)在想想,如果當(dāng)時(shí)用這個(gè)函數(shù)的話,將使多么的方便。函數(shù)原型:

CString SpanExcluding( LPCTSTR lpszCharSet ) const;

它查找CString對(duì)象中與lpszCharSet串中任意匹配的第一個(gè)字符,并返回一個(gè)CString對(duì)象,該對(duì)象的內(nèi)容是原來對(duì)象從起始位置到查找到字符的前一個(gè)字符的部分。這在分離用分割符(逗號(hào)空格之類)隔開的子串的時(shí)候?qū)⑹址奖悖?br>
       str1 = “Hello test”;

       str2 = str1.SpanExcluding(“ ,”);

       afxDump << str2;         //輸出”Hello”

同時(shí),還有一個(gè)很方便的函數(shù):CString::SpanIncluding,函數(shù)原型:

CString SpanIncluding( LPCTSTR lpszCharSet ) const;

它返回對(duì)象中前若干個(gè)字符,這些字符都必須在lpszCharSet之中:

       str1 = “Hello test”;

       str2 = str1.SpanIncluding(“ABCDEFGHIJK”);

       afxDump << str2;         //輸出”H”

→插入子串:用CString::Insert可以插入字符或者字串到指定位置

       str1 = “Hello test”;

       str1.Insert(2,“ABCD”);

       afxDump << str1;         //輸出”HeABCDllo test”

→替換:CString::Replace的作用是將原來對(duì)象中的所有匹配相替換指定字符/子串。有兩個(gè)重載原型:

int Replace( TCHAR chOld, TCHAR chNew );

int Replace( LPCTSTR lpszOld, LPCTSTR lpszNew );

☆CString對(duì)象的屬性操作:這些都很常用了,簡(jiǎn)要說明之

int GetLength( ) const;          //獲得buffer的長(zhǎng)度

BOOL IsEmpty( ) const;              //判斷CString對(duì)象內(nèi)容是否為空

int Compare( LPCTSTR lpsz ) const;   //與lpsz按ASCII碼比較

int CompareNoCase( LPCTSTR lpsz ) const;             //與lpsz按ASCII碼比較,忽略大小寫

CString::Format             /*用來格式化對(duì)象。切記不要把對(duì)象本身放到Format函數(shù)的參數(shù)中去了*/

原理:

Cstring就是對(duì)一個(gè)用來存放字符串的緩沖區(qū)和對(duì)施加于這個(gè)字符串的操作封裝。也就是說,Cstring里需要有一個(gè)用來存放字符串的緩沖區(qū),并且有一個(gè)指針指向該緩沖區(qū),該指針就是LPTSTR m_pchData。但是有些字符串操作會(huì)增建或減少字符串的長(zhǎng)度,因此為了減少頻繁的申請(qǐng)內(nèi)存或者釋放內(nèi)存,Cstring會(huì)先申請(qǐng)一個(gè)大的內(nèi)存塊用來存放字符串。這樣,以后當(dāng)字符串長(zhǎng)度增長(zhǎng)時(shí),如果增加的總長(zhǎng)度不超過預(yù)先申請(qǐng)的內(nèi)存塊的長(zhǎng)度,就不用再申請(qǐng)內(nèi)存。當(dāng)增加后的字符串長(zhǎng)度超過預(yù)先申請(qǐng)的內(nèi)存時(shí),Cstring先釋放原先的內(nèi)存,然后再重新申請(qǐng)一個(gè)更大的內(nèi)存塊。同樣的,當(dāng)字符串長(zhǎng)度減少時(shí),也不釋放多出來的內(nèi)存空間。而是等到積累到一定程度時(shí),才一次性將多余的內(nèi)存釋放。

還有,當(dāng)使用一個(gè)Cstring對(duì)象a來初始化另一個(gè)Cstring對(duì)象b時(shí),為了節(jié)省空間,新對(duì)象b并不分配空間,它所要做的只是將自己的指針指向?qū)ο骯的那塊內(nèi)存空間,只有當(dāng)需要修改對(duì)象a或者b中的字符串時(shí),才會(huì)為新對(duì)象b申請(qǐng)內(nèi)存空間,這叫做寫入復(fù)制技術(shù)(CopyBeforeWrite)。

這樣,僅僅通過一個(gè)指針就不能完整的描述這塊內(nèi)存的具體情況,需要更多的信息來描述。

首先,需要有一個(gè)變量來描述當(dāng)前內(nèi)存塊的總的大小。

其次,需要一個(gè)變量來描述當(dāng)前內(nèi)存塊已經(jīng)使用的情況。也就是當(dāng)前字符串的長(zhǎng)度

另外,還需要一個(gè)變量來描述該內(nèi)存塊被其他Cstring引用的情況。有一個(gè)對(duì)象引用該內(nèi)存塊,就將該數(shù)值加一。

Cstring中專門定義了一個(gè)結(jié)構(gòu)體來描述這些信息:

struct CStringData

{

   long nRefs;             // reference count

   int nDataLength;        // length of data (including terminator)

   int nAllocLength;       // length of allocation

   // TCHAR data[nAllocLength]

   TCHAR* data()           // TCHAR* to managed data

               { return (TCHAR*)(this+1); }

};

實(shí)際使用時(shí),該結(jié)構(gòu)體的所占用的內(nèi)存塊大小是不固定的,在Cstring內(nèi)部的內(nèi)存塊頭部,放置的是該結(jié)構(gòu)體。從該內(nèi)存塊頭部開始的sizeof(CstringData)個(gè)BYTE后才是真正的用于存放字符串的內(nèi)存空間。這種結(jié)構(gòu)的數(shù)據(jù)結(jié)構(gòu)的申請(qǐng)方法是這樣實(shí)現(xiàn)的:

pData = (CStringData*) new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];

pData->nAllocLength = nLen;

其中nLen是用于說明需要一次性申請(qǐng)的內(nèi)存空間的大小的。

從代碼中可以很容易的看出,如果想申請(qǐng)一個(gè)256個(gè)TCHAR的內(nèi)存塊用于存放字符串,實(shí)際申請(qǐng)的大小是:

sizeof(CstringData)個(gè)BYTE + (nLen+1)個(gè)TCHAR

其中前面sizeof(CstringData)個(gè)BYTE是用來存放CstringData信息的。后面的nLen+1個(gè)TCHAR才是真正用來存放字符串的,多出來的一個(gè)用來存放’\0’。

Cstring中所有的operations的都是針對(duì)這個(gè)緩沖區(qū)的。比如LPTSTR CString::GetBuffer(int nMinBufLength),它的實(shí)現(xiàn)方法是:

首先通過Cstring::GetData()取得CstringData對(duì)象的指針。該指針是通過存放字符串的指針m_pchData先后偏移sizeof(CstringData),從而得到了CstringData的地址。

然后根據(jù)參數(shù)nMinBufLength給定的值重新實(shí)例化一個(gè)CstringData對(duì)象,使得新的對(duì)象里的字符串緩沖長(zhǎng)度能夠滿足nMinBufLength。

然后在重新設(shè)置一下新的CstringData中的一些描述值。

最后將新CstringData對(duì)象里的字符串緩沖直接返回給調(diào)用者。

這些過程用C++代碼描述就是:

   if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)

   {

               // we have to grow the buffer

               CStringData* pOldData = GetData();

               int nOldLen = GetData()->nDataLength;   // AllocBuffer will tromp it

               if (nMinBufLength < nOldLen)

                           nMinBufLength = nOldLen;

               AllocBuffer(nMinBufLength);

               memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(TCHAR));

               GetData()->nDataLength = nOldLen;

               CString::Release(pOldData);

   }

   ASSERT(GetData()->nRefs <= 1);

   // return a pointer to the character storage for this string

   ASSERT(m_pchData != NULL);

   return m_pchData;

很多時(shí)候,我們經(jīng)常的對(duì)大批量的字符串進(jìn)行互相拷貝修改等,Cstring 使用了CopyBeforeWrite技術(shù)。使用這種方法,當(dāng)利用一個(gè)Cstring對(duì)象a實(shí)例化另一個(gè)對(duì)象b的時(shí)候,其實(shí)兩個(gè)對(duì)象的數(shù)值是完全相同的,但是如果簡(jiǎn)單的給兩個(gè)對(duì)象都申請(qǐng)內(nèi)存的話,對(duì)于只有幾個(gè)、幾十個(gè)字節(jié)的字符串還沒有什么,如果是一個(gè)幾K甚至幾M的數(shù)據(jù)量來說,是一個(gè)很大的浪費(fèi)。

因此Cstring 在這個(gè)時(shí)候只是簡(jiǎn)單的將新對(duì)象b的字符串地址m_pchData直接指向另一個(gè)對(duì)象a的字符串地址m_pchData。所做的額外工作是將對(duì)象a的內(nèi)存應(yīng)用CstringData:: nRefs加一。

CString::CString(const CString& stringSrc)

{

               m_pchData = stringSrc.m_pchData;

               InterlockedIncrement(&GetData()->nRefs);

}


這樣當(dāng)修改對(duì)象a或?qū)ο骲的字符串內(nèi)容時(shí),首先檢查CstringData:: nRefs的值,如果大于一(等于一,說明只有自己一個(gè)應(yīng)用該內(nèi)存空間),說明該對(duì)象引用了別的對(duì)象內(nèi)存或者自己的內(nèi)存被別人應(yīng)用,該對(duì)象首先將該應(yīng)用值減一,然后將該內(nèi)存交給其他的對(duì)象管理,自己重新申請(qǐng)一塊內(nèi)存,并將原來內(nèi)存的內(nèi)容拷貝過來。

其實(shí)現(xiàn)的簡(jiǎn)單代碼是:

void CString::CopyBeforeWrite()

{

   if (GetData()->nRefs > 1)

   {

               CStringData* pData = GetData();

               Release();

               AllocBuffer(pData->nDataLength);

memcpy(m_pchData, pData->data(),

            (pData- >nDataLength+1)*sizeof(TCHAR));

   }

}

其中Release 就是用來判斷該內(nèi)存的被引用情況的。

void CString::Release()

{

   if (GetData() != _afxDataNil)

   {

               if (InterlockedDecrement(&GetData()->nRefs) <= 0)

                           FreeData(GetData());

   }

}

當(dāng)多個(gè)對(duì)象共享同一塊內(nèi)存時(shí),這塊內(nèi)存就屬于多個(gè)對(duì)象,而不在屬于原來的申請(qǐng)這塊內(nèi)存的那個(gè)對(duì)象了。但是,每個(gè)對(duì)象在其生命結(jié)束時(shí),都首先將這塊內(nèi)存的引用減一,然后再判斷這個(gè)引用值,如果小于等于零時(shí),就將其釋放,否則,將之交給另外的正在引用這塊內(nèi)存的對(duì)象控制。

Cstring使用這種數(shù)據(jù)結(jié)構(gòu),對(duì)于大數(shù)據(jù)量的字符串操作,可以節(jié)省很多頻繁申請(qǐng)釋放內(nèi)存的時(shí)間,有助于提升系統(tǒng)性能。

通過上面的分析,我們已經(jīng)對(duì)Cstring的內(nèi)部機(jī)制已經(jīng)有了一個(gè)大致的了解了??偟恼f來MFC中的Cstring是比較成功的。但是,由于數(shù)據(jù)結(jié)構(gòu)比較復(fù)雜(使用CstringData),所以在使用的時(shí)候就出現(xiàn)了很多的問題,最典型的一個(gè)就是用來描述內(nèi)存塊屬性的屬性值和實(shí)際的值不一致。出現(xiàn)這個(gè)問題的原因就是Cstring為了方便某些應(yīng)用,提供了一些operations,這些operation可以直接返回內(nèi)存塊中的字符串的地址值,用戶可以通過對(duì)這個(gè)地址值指向的地址進(jìn)行修改,但是,修改后又沒有調(diào)用相應(yīng)的operations1使CstringData中的值來保持一致。比如,用戶可以首先通過operations得到字符串地址,然后將一些新的字符增加到這個(gè)字符串中,使得字符串的長(zhǎng)度增加,但是,由于是直接通過指針修改的,所以描述該字符串長(zhǎng)度的CstringData中的nDataLength卻還是原來的長(zhǎng)度,因此當(dāng)通過GetLength獲取字符串長(zhǎng)度時(shí),返回的必然是不正確的。

存在這些問題的operations下面一一介紹。

1.      GetBuffer

很多錯(cuò)誤用法中最典型的一個(gè)就是Cstring:: GetBuffer ()了.查了MSDN,里面對(duì)這個(gè)operation的描述是:

Returns a pointer to the internal character buffer for the CString object. The returned LPTSTR is not const and thus allows direct modification of CString contents。

這段很清楚的說明,對(duì)于這個(gè)operation返回的字符串指針,我們可以直接修改其中的值:

   CString str1("This is the string 1");――――――――――――――――1

   int nOldLen = str1.GetLength();―――――――――――――――――2

   char* pstr1 = str1.GetBuffer( nOldLen );――――――――――――――3

   strcpy( pstr1, "modified" );――――――――――――――――――――4

   int nNewLen = str1.GetLength();―――――――――――――――――5

通過設(shè)置斷點(diǎn),我們來運(yùn)行并跟蹤這段代碼可以看出,當(dāng)運(yùn)行到三處時(shí),str1的值是”This is the string 1”,并且nOldLen的值是20。當(dāng)運(yùn)行到5處時(shí),發(fā)現(xiàn),str1的值變成了”modified”。也就是說,對(duì)GetBuffer返回的字符串指針,我們將它做為參數(shù)傳遞給strcpy,試圖來修改這個(gè)字符串指針指向的地址,結(jié)果是修改成功,并且Cstring對(duì)象str1的值也響應(yīng)的變成了” modified”。但是,我們接著再調(diào)用str1.GetLength()時(shí)卻意外的發(fā)現(xiàn)其返回值仍然是20,但是實(shí)際上此時(shí)str1中的字符串已經(jīng)變成了” modified”,也就是說這個(gè)時(shí)候返回的值應(yīng)該是字符串” modified”的長(zhǎng)度8!而不是20?,F(xiàn)在Cstring工作已經(jīng)不正常了!這是怎么回事?

很顯然,str1工作不正常是在對(duì)通過GetBuffer返回的指針進(jìn)行一個(gè)字符串拷貝之后的。

再看MSDN上的關(guān)于這個(gè)operation的說明,可以看到里面有這么一段話:

If you use the pointer returned by GetBuffer to change the string contents, you must call ReleaseBuffer before using any other CString member s.

原來在對(duì)GetBuffer返回的指針使用之后需要調(diào)用ReleaseBuffer,這樣才能使用其他Cstring的operations。上面的代碼中,我們?cè)?-5處增建一行代碼:str2.ReleaseBuffer(),然后再觀察nNewLen,發(fā)現(xiàn)這個(gè)時(shí)候已經(jīng)是我們想要的值8了。

從Cstring的機(jī)理上也可以看出:GetBuffer返回的是CstringData對(duì)象里的字符串緩沖的首地址。根據(jù)這個(gè)地址,我們對(duì)這個(gè)地址里的值進(jìn)行的修改,改變的只是CstringData里的字符串緩沖中的值, CstringData中的其他用來描述字符串緩沖的屬性的值已經(jīng)不是正確的了。比如此時(shí)CstringData:: nDataLength很顯然還是原來的值20,但是現(xiàn)在實(shí)際上字符串的長(zhǎng)度已經(jīng)是8了。也就是說我們還需要對(duì)CstringData中的其他值進(jìn)行修改。這也就是需要調(diào)用ReleaseBuffer()的原因了。

正如我們所預(yù)料的,ReleaseBuffer源代碼中顯示的正是我們所猜想的:

   CopyBeforeWrite(); // just in case GetBuffer was not called

   if (nNewLength == -1)

               nNewLength = lstrlen(m_pchData); // zero terminated

   ASSERT(nNewLength <= GetData()->nAllocLength);

   GetData()->nDataLength = nNewLength;

   m_pchData[nNewLength] = ''''\0'''';

其中CopyBeforeWrite是實(shí)現(xiàn)寫拷貝技術(shù)的,這里不管它。

下面的代碼就是重新設(shè)置CstringData對(duì)象中描述字符串長(zhǎng)度的那個(gè)屬性值的。首先取得當(dāng)前字符串的長(zhǎng)度,然后通過GetData()取得CstringData的對(duì)象指針,并修改里面的nDataLength成員值。

但是,現(xiàn)在的問題是,我們雖然知道了錯(cuò)誤的原因,知道了當(dāng)修改了GetBuffer返回的指針?biāo)赶虻闹抵笮枰{(diào)用ReleaseBuffer才能使用Cstring的其他operations時(shí),我們就能避免不在犯這個(gè)錯(cuò)誤了。答案是否定的。這就像雖然每一個(gè)懂一點(diǎn)編程知識(shí)的人都知道通過new申請(qǐng)的內(nèi)存在使用完以后需要通過delete來釋放一樣,道理雖然很簡(jiǎn)單,但是,最后實(shí)際的結(jié)果還是有由于忘記調(diào)用delete而出現(xiàn)了內(nèi)存泄漏。
實(shí)際工作中,常常是對(duì)GetBuffer返回的值進(jìn)行了修改,但是最后卻忘記調(diào)用ReleaseBuffer來釋放。而且,由于這個(gè)錯(cuò)誤不象new和delete人人都知道的并重視的,因此也沒有一個(gè)檢查機(jī)制來專門檢查,所以最終程序中由于忘記調(diào)用ReleaseBuffer而引起的錯(cuò)誤被帶到了發(fā)行版本中。

要避免這個(gè)錯(cuò)誤,方法很多。但是最簡(jiǎn)單也是最有效的就是避免這種用法。很多時(shí)候,我們并不需要這種用法,我們完全可以通過其他的安全方法來實(shí)現(xiàn)。

比如上面的代碼,我們完全可以這樣寫:

   CString str1("This is the string 1");

   int nOldLen = str1.GetLength();

   str1 = "modified";

   int nNewLen = str1.GetLength();

但是有時(shí)候確實(shí)需要,比如:

我們需要將一個(gè)Cstring對(duì)象中的字符串進(jìn)行一些轉(zhuǎn)換,這個(gè)轉(zhuǎn)換是通過調(diào)用一個(gè)dll里的函數(shù)Translate來完成的,但是要命的是,不知道什么原因,這個(gè)函數(shù)的參數(shù)使用的是char*型的:

DWORD Translate( char* pSrc, char *pDest, int nSrcLen, int nDestLen );

這個(gè)時(shí)候我們可能就需要這個(gè)方法了:

Cstring strDest;

Int nDestLen = 100;

DWORD dwRet = Translate( _strSrc.GetBuffer( _strSrc.GetLength() ),

strDest.GetBuffer(nDestLen),

_strSrc.GetLength(), nDestlen );

_strSrc.ReleaseBuffer();

strDest.ReleaseBuffer();

if ( SUCCESSCALL(dwRet) )

{

}

if ( FAILEDCALL(dwRet) )

{

}

的確,這種情況是存在的,但是,我還是建議盡量避免這種用法,如果確實(shí)需要使用,請(qǐng)不要使用一個(gè)專門的指針來保存GetBuffer返回的值,因?yàn)檫@樣常常會(huì)讓我們忘記調(diào)用ReleaseBuffer。就像上面的代碼,我們可以在調(diào)用GetBuffer之后馬上就調(diào)用ReleaseBuffer來調(diào)整Cstring對(duì)象。

2.      LPCTSTR

關(guān)于LPCTSTR的錯(cuò)誤常常發(fā)生在初學(xué)者身上。

例如在調(diào)用函數(shù)

DWORD Translate( char* pSrc, char *pDest, int nSrcLen, int nDestLen );

時(shí),初學(xué)者常常使用的方法就是:

int nLen = _strSrc.GetLength();

DWORD dwRet = Translate( (char*)(LPCTSTR)_strSrc),

(char*)(LPCTSTR)_strSrc),

nLen,

nLen);

if ( SUCCESSCALL(dwRet) )

{

}

if ( FAILEDCALL(dwRet) )

{

}

他原本的初衷是將轉(zhuǎn)換后的字符串仍然放在_strSrc中,但是,當(dāng)調(diào)用完Translate以后之后再使用_strSrc時(shí),卻發(fā)現(xiàn)_strSrc已經(jīng)工作不正常了。檢查代碼卻又找不到問題到底出在哪里。

其實(shí)這個(gè)問題和第一個(gè)問題是一樣的。Cstring類已經(jīng)將LPCTST重載了。在Cstring中LPCTST實(shí)際上已經(jīng)是一個(gè)operation了。對(duì)LPCTST的調(diào)用實(shí)際上和GetBuffer是類似的,直接返回CstringData對(duì)象中的字符串緩沖的首地址。

其C++代碼實(shí)現(xiàn)是:

_AFX_INLINE CString::operator LPCTSTR() const

   { return m_pchData; }

因此在使用完以后同樣需要調(diào)用ReleaseBuffer()。

但是,這個(gè)誰又能看出來呢?

其實(shí)這個(gè)問題的本質(zhì)原因出在類型轉(zhuǎn)換上。LPCTSTR返回的是一個(gè)const char*類型,因此使用這個(gè)指針來調(diào)用Translate編譯是不能通過的。對(duì)于一個(gè)初學(xué)者,或者一個(gè)有很長(zhǎng)編程經(jīng)驗(yàn)的人都會(huì)再通過強(qiáng)行類型轉(zhuǎn)換將const char*轉(zhuǎn)換為char*。最終造成了Cstring工作不正常,并且這樣也很容易造成緩沖溢出。

通過上面對(duì)于Cstring機(jī)制和一些容易出現(xiàn)的使用錯(cuò)誤的描述,可以使我們更好的使用Cstring

Feedback

# re: CString類的使用(轉(zhuǎn))  回復(fù)  更多評(píng)論   

2009-08-14 20:31 by ss
總結(jié)的不錯(cuò)

只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            激情文学综合丁香| 久久激五月天综合精品| 亚洲男女自偷自拍图片另类| 亚洲精品日韩在线观看| 国产精品九色蝌蚪自拍| 久久不见久久见免费视频1| 99v久久综合狠狠综合久久| 亚洲人成在线影院| 99国产麻豆精品| 亚洲一区中文| 久久性色av| 欧美日韩国产综合一区二区 | 亚洲欧美日韩精品久久奇米色影视 | 亚洲欧洲免费视频| 亚洲深爱激情| 久久在线播放| 日韩视频在线观看免费| 亚洲一区二区不卡免费| 久久乐国产精品| 欧美视频日韩视频| 精品不卡一区二区三区| 99re视频这里只有精品| 久久av在线看| 亚洲国产黄色| 欧美在线资源| 欧美精品在线一区| 激情欧美一区二区| 亚洲欧美激情一区| 亚洲第一级黄色片| 亚洲欧美日韩综合一区| 欧美jizz19hd性欧美| 国产精品亚洲成人| 亚洲香蕉在线观看| 欧美激情免费观看| 欧美专区日韩专区| 国产精品久久久久久久第一福利| 在线成人中文字幕| 欧美在线观看你懂的| 91久久精品日日躁夜夜躁欧美| 久久国产精品久久w女人spa| 欧美午夜在线| 99视频有精品| 亚洲东热激情| 久久久久久久97| 国产亚洲午夜| 欧美一区中文字幕| 亚洲午夜精品久久久久久浪潮| 欧美福利影院| 亚洲黄色在线观看| 免费看亚洲片| 久久久亚洲国产美女国产盗摄| 国产免费成人| 欧美亚洲三级| 亚洲淫性视频| 国产精品视频专区| 午夜亚洲福利| 亚洲欧美日韩成人高清在线一区| 免费视频一区| 欧美在线免费播放| 国产精品一区二区a| 亚洲午夜精品久久久久久app| 亚洲人成久久| 欧美日韩亚洲不卡| 中文国产成人精品久久一| 99国产精品久久久久久久成人热| 欧美精品一区二| 一区二区三区国产精品| 日韩小视频在线观看| 欧美午夜精品电影| 欧美在线综合| 久久精品视频免费播放| 亚洲国产精品电影| 亚洲日本理论电影| 欧美日韩国产高清| 亚洲欧美日韩第一区| 亚洲一区中文字幕在线观看| 国产一区二区0| 欧美粗暴jizz性欧美20| 老色鬼久久亚洲一区二区| 亚洲人妖在线| 一本一本久久a久久精品综合妖精 一本一本久久a久久精品综合麻豆 | 日韩视频免费观看高清完整版| 欧美久久久久| 亚洲欧美日韩精品久久奇米色影视 | 午夜精品免费在线| 亚洲系列中文字幕| 在线观看亚洲一区| 一本久久a久久免费精品不卡| 国产精品一区在线观看你懂的| 久久九九免费| 欧美破处大片在线视频| 亚洲欧美中日韩| 久久男人资源视频| 亚洲一区二区三区四区在线观看| 欧美一级片一区| 99精品欧美一区二区三区| 亚洲一区二区动漫| 亚洲三级免费| 欧美一区二区三区精品| 亚洲精品在线免费| 久久av资源网| 亚洲一区黄色| 久久另类ts人妖一区二区| 亚洲欧美国产不卡| 麻豆成人在线观看| 久久精品国产亚洲aⅴ| 欧美日韩精品不卡| 久久人人看视频| 国产精品豆花视频| 亚洲国产高清自拍| 99热精品在线观看| 鲁大师成人一区二区三区| 欧美剧在线免费观看网站| 久久久久久久久久久久久久一区| 欧美日韩国产探花| 欧美电影资源| 国产日韩欧美在线播放| 亚洲老司机av| 亚洲日韩欧美视频一区| 久久久久久九九九九| 欧美一区二区黄色| 国产精品久久久久久久久免费桃花| 亚洲丰满少妇videoshd| 黑人操亚洲美女惩罚| 亚洲欧美欧美一区二区三区| 一区二区三区四区国产| 狂野欧美性猛交xxxx巴西| 久久亚洲国产精品一区二区| 国产精品国产成人国产三级| 日韩系列欧美系列| 正在播放亚洲一区| 欧美精品久久99| 亚洲第一福利视频| 亚洲伦理在线免费看| 久久艳片www.17c.com| 鲁大师成人一区二区三区 | 99re6这里只有精品| 久久综合给合久久狠狠狠97色69| 久久精品人人做人人爽| 国产日韩欧美中文| 小嫩嫩精品导航| 久久久久久婷| 亚洲福利av| 欧美成人在线影院| 亚洲欧洲综合| 亚洲专区免费| 国产精品一级| 欧美一区二区日韩一区二区| 久久九九全国免费精品观看| 黑丝一区二区三区| 麻豆freexxxx性91精品| 亚洲成人在线网站| 亚洲色图在线视频| 国产精品美女www爽爽爽视频| 午夜伦欧美伦电影理论片| 久久天天躁狠狠躁夜夜av| 亚洲国产91| 欧美区日韩区| 亚洲欧美日韩国产中文| 久久精品视频一| 亚洲日本中文字幕| 国产精品初高中精品久久| 午夜免费日韩视频| 欧美激情一级片一区二区| 亚洲五月六月| 激情综合中文娱乐网| 欧美久久视频| 欧美在线免费视屏| 亚洲精品在线视频| 久久精品视频在线播放| 亚洲理论在线观看| 国产欧美一区二区三区国产幕精品| 久久久www成人免费毛片麻豆| 亚洲国产精品久久久久秋霞不卡 | 亚洲第一精品夜夜躁人人躁| 亚洲色图综合久久| 日韩午夜一区| 久久美女艺术照精彩视频福利播放| 欧美激情精品久久久久久蜜臀 | 媚黑女一区二区| 一区二区三区精品久久久| 韩日欧美一区| 国产精品qvod| 老司机67194精品线观看| 亚洲一区二区三区四区五区午夜| 老鸭窝亚洲一区二区三区| 在线视频亚洲一区| 亚洲国产精品成人va在线观看| 国产精品久久久久国产a级| 老巨人导航500精品| 亚洲综合久久久久| 99爱精品视频| 亚洲日本成人| 欧美成人性生活| 久久久777| 翔田千里一区二区| 亚洲视频精选在线| 99视频精品在线| 亚洲精品少妇30p| 在线欧美日韩|