日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

(轉(zhuǎn))CString詳解以及CString轉(zhuǎn)換成char* LPCTSTR LPSTR T...

 xihayouyi 2011-01-21

(轉(zhuǎn))CString詳解以及CString轉(zhuǎn)換成char* LPCTSTR LPSTR TCHAR*

學(xué)習(xí)歷程 2010-04-26 22:34:15 閱讀588 評(píng)論0   字號(hào): 訂閱

就是因?yàn)椴惶珪?huì)正確地用CString和它的成員函數(shù),以至于運(yùn)行不出任何錯(cuò)誤,就是得不到想要的結(jié)果,讓我郁悶了一天,還要這篇轉(zhuǎn)來(lái)的文章里的一句話(下面我用紅色標(biāo)出來(lái)的部分)就結(jié)束了我的“郁悶“。感謝愿意分享的人。

CString詳解以及CString轉(zhuǎn)換成char* CString 型和 char* 類型的相互轉(zhuǎn)化1.CString 轉(zhuǎn)化成 char* 之一:強(qiáng)制類型轉(zhuǎn)換為 LPCTSTR;

  這是一種略微硬性的轉(zhuǎn)換,有關(guān)“正確”的做法,人們?cè)谡J(rèn)識(shí)上還存在許多混亂,正確的使用方法有很多,但錯(cuò)誤的使用方法可能與正確的使用方法一樣多。

  我們首先要了解 CString 是一種很特殊的 C++ 對(duì)象,它里面包含了三個(gè)值:一個(gè)指向某個(gè)數(shù)據(jù)緩沖區(qū)的指針、一個(gè)是該緩沖中有效的字符記數(shù)以及一個(gè)緩沖區(qū)長(zhǎng)度。 有效字符數(shù)的大小可以是從0到該緩沖最大長(zhǎng)度值減1之間的任何數(shù)(因?yàn)樽址Y(jié)尾有一個(gè)NULL字符)。字符記數(shù)和緩沖區(qū)長(zhǎng)度被巧妙隱藏。

  除非你做一些特殊的操作,否則你不可能知道給CString對(duì)象分配的緩沖區(qū)的長(zhǎng)度。這樣,即使你獲得了該0緩沖的地址,你也無(wú)法更改其中的內(nèi)容,不能截短字符串,也 絕對(duì)沒有辦法加長(zhǎng)它的內(nèi)容,否則第一時(shí)間就會(huì)看到溢出。

  LPCTSTR 操作符(或者更明確地說(shuō)就是 TCHAR * 操作符)在 CString 類中被重載了,該操作符的定義是返回緩沖區(qū)的地址,因此,如果你需要一個(gè)指向 CString 的 字符串指針的話,可以這樣做:

CString s("GrayCat");

LPCTSTR p = s;

  它可以正確地運(yùn)行。這是由C語(yǔ)言的強(qiáng)制類型轉(zhuǎn)化規(guī)則實(shí)現(xiàn)的。當(dāng)需要強(qiáng)制類型轉(zhuǎn)化時(shí),C++規(guī)測(cè)容許這種選擇。比如,你可以將(浮點(diǎn)數(shù))定義為將某個(gè)復(fù)數(shù) (有一對(duì)浮點(diǎn)數(shù))進(jìn)行強(qiáng)制類型轉(zhuǎn)換后只返回該復(fù)數(shù)的第一個(gè)浮點(diǎn)數(shù)(也就是其實(shí)部)??梢韵笙旅孢@樣:

Complex c(1.2f, 4.8f);

float realpart = c;

如果(float)操作符定義正確的話,那么實(shí)部的的值應(yīng)該是1.2。

  這種強(qiáng)制轉(zhuǎn)化適合所有這種情況,例如,任何帶有 LPCTSTR 類型參數(shù)的函數(shù)都會(huì)強(qiáng)制執(zhí)行這種轉(zhuǎn)換。 于是,你可能有這樣一個(gè)函數(shù)(也許在某個(gè)你買來(lái)的DLL中):

BOOL DoSomethingCool(LPCTSTR s);

你象下面這樣調(diào)用它:

CString file("c:\\myfiles\\coolstuff")

BOOL result = DoSomethingCool(file);

  它能正確運(yùn)行。因?yàn)?DoSomethingCool 函數(shù)已經(jīng)說(shuō)明了需要一個(gè) LPCTSTR 類型的參數(shù),因此 LPCTSTR 被應(yīng)用于該參數(shù),在 MFC 中就是返回的串地址。

如果你要格式化字符串怎么辦呢?

CString graycat("GrayCat");

CString s;

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

  注意由于在可變參數(shù)列表中的值(在函數(shù)說(shuō)明中是以“...”表示的)并沒有隱含一個(gè)強(qiáng)制類型轉(zhuǎn)換操作符。你會(huì)得到什么結(jié)果呢?

  一個(gè)令人驚訝的結(jié)果,我們得到的實(shí)際結(jié)果串是:

"Mew! I love GrayCat"。

  因?yàn)?MFC 的設(shè)計(jì)者們?cè)谠O(shè)計(jì) CString 數(shù)據(jù)類型時(shí)非常小心, CString 類型表達(dá)式求值后指向了字符串,所以這里看不到任何象 Format 或 sprintf 中的強(qiáng)制類型轉(zhuǎn)換,你仍然可以得到正確的行為。描述 CString 的附加數(shù)據(jù)實(shí)際上在 CString 名義地址之后。

  有一件事情你是不能做的,那就是修改字符串。比如,你可能會(huì)嘗試用“,”代替“.”(不要做這樣的,如果你在乎國(guó)際化問(wèn)題,你應(yīng)該使用十進(jìn)制轉(zhuǎn)換的 National Language Support 特性,),下面是個(gè)簡(jiǎn)單的例子:

CString v("1.00"); // 貨幣金額,兩位小數(shù)

LPCTSTR p = v;

p[lstrlen(p) - 3] = '','';

  這時(shí)編譯器會(huì)報(bào)錯(cuò),因?yàn)槟阗x值了一個(gè)常量串。如果你做如下嘗試,編譯器也會(huì)錯(cuò):

strcat(p, "each");

  因?yàn)?strcat 的第一個(gè)參數(shù)應(yīng)該是 LPTSTR 類型的數(shù)據(jù),而你卻給了一個(gè) LPCTSTR。

  不要試圖鉆這個(gè)錯(cuò)誤消息的牛角尖,這只會(huì)使你自己陷入麻煩!

  原因是緩沖有一個(gè)計(jì)數(shù),它是不可存取的(它位于 CString 地址之下的一個(gè)隱西藏域),如果你改變這個(gè)串,緩沖中的字符計(jì)數(shù)不會(huì)反映所做的修改。此外,如果字符串長(zhǎng)度恰好是該字符串物理限制的長(zhǎng)度(梢后還會(huì)講到這個(gè)問(wèn)題),那么擴(kuò)展該字符串將改寫緩沖以外的任何數(shù)據(jù),那是你無(wú)權(quán)進(jìn)行寫操作的內(nèi)存(不對(duì)嗎?),你會(huì)毀換壞不屬于你的內(nèi)存。這是應(yīng)用程序真正的死亡處方。

2. CString轉(zhuǎn)化成char* 之二:使用 CString 對(duì)象的 GetBuffer 方法;

  如果你需要修改 CString 中的內(nèi)容,它有一個(gè)特殊的方法可以使用,那就是 GetBuffer,它的作用是返回一個(gè)可寫的緩沖指針。 如果你只是打算修改字符或者截短字符串,你完全可以這樣做:

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();

  這是 GetBuffer 的第一種用法,也是最簡(jiǎn)單的一種,不用給它傳遞參數(shù),它使用默認(rèn)值 0,意思是:“給我這個(gè)字符串的指針,我保證不加長(zhǎng)它”。當(dāng)你調(diào)用 ReleaseBuffer 時(shí),字符串的實(shí)際長(zhǎng)度會(huì)被重新計(jì)算,然后存入 CString 對(duì)象中。

  必須強(qiáng)調(diào)一點(diǎn),在 GetBuffer 和 ReleaseBuffer 之間這個(gè)范圍,一定不能使用你要操作的這個(gè)緩沖的 CString 對(duì)象的任何方法。因?yàn)?ReleaseBuffer 被調(diào)用之前,該 CString 對(duì)象的完整性得不到保障。研究以下代碼:

CString s(...);

LPTSTR p = s.GetBuffer();

//... 這個(gè)指針 p 發(fā)生了很多事情

int n = s.GetLength(); // 很糟D!!!!! 有可能給出錯(cuò)誤的答案!!!

s.TrimRight(); // 很糟!!!!! 不能保證能正常工作!!!!

s.ReleaseBuffer(); // 現(xiàn)在應(yīng)該 OK

int m = s.GetLength(); // 這個(gè)結(jié)果可以保證是正確的。

s.TrimRight(); // 將正常工作。

  假設(shè)你想增加字符串的長(zhǎng)度,你首先要知道這個(gè)字符串可能會(huì)有多長(zhǎng),好比是聲明字符串?dāng)?shù)組的時(shí)候用:

char buffer[1024];

表示 1024 個(gè)字符空間足以讓你做任何想做得事情。在 CString 中與之意義相等的表示法:

LPTSTR p = s.GetBuffer(1024);

  調(diào)用這個(gè)函數(shù)后,你不僅獲得了字符串緩沖區(qū)的指針,而且同時(shí)還獲得了長(zhǎng)度至少為 1024 個(gè)字符的空間(注意,我說(shuō)的是“字符”,而不是“字節(jié)”,因?yàn)?CString 是以隱含方式感知 Unicode 的)。

  同時(shí),還應(yīng)該注意的是,如果你有一個(gè)常量串指針,這個(gè)串本身的值被存儲(chǔ)在只讀內(nèi)存中,如果試圖存儲(chǔ)它,即使你已經(jīng)調(diào)用了 GetBuffer ,并獲得一個(gè)只讀內(nèi)存的指針,存入操作會(huì)失敗,并報(bào)告存取錯(cuò)誤。我沒有在 CString 上證明這一點(diǎn),但我看到過(guò)大把的 C 程序員經(jīng)常犯這個(gè)錯(cuò)誤。

  C 程序員有一個(gè)通病是分配一個(gè)固定長(zhǎng)度的緩沖,對(duì)它進(jìn)行 sprintf 操作,然后將它賦值給一個(gè) CString:

char buffer[256];

sprintf(buffer, "%......", args, ...); // ... 部分省略許多細(xì)節(jié)

CString s = buffer;

雖然更好的形式可以這么做:

CString s;

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

如果你的字符串長(zhǎng)度萬(wàn)一超過(guò) 256 個(gè)字符的時(shí)候,不會(huì)破壞堆棧。

  另外一個(gè)常見的錯(cuò)誤是:既然固定大小的內(nèi)存不工作,那么就采用動(dòng)態(tài)分配字節(jié),這種做法弊端更大:

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;

它可以能被簡(jiǎn)單地寫成:

CString s;

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

  需要注意 sprintf 例子都不是 Unicode 就緒的,盡管你可以使用 tsprintf 以及用 _T() 來(lái)包圍格式化字符串,但是基本 思路仍然是在走彎路,這這樣很容易出錯(cuò)。

3、CString 和臨時(shí)對(duì)象

  這是出現(xiàn)在 microsoft.public.vc.mfc 新聞組中的一個(gè)小問(wèn)題,我簡(jiǎn)單的提一下,這個(gè)問(wèn)題是有個(gè)程序員需要往注冊(cè)表中寫入一個(gè)字符串,他寫道:

  我試著用 RegSetValueEx() 設(shè)置一個(gè)注冊(cè)表鍵的值,但是它的結(jié)果總是令我困惑。當(dāng)我用char[]聲明一個(gè)變量時(shí)它能正常工作,但是當(dāng)我用 CString 的時(shí)候,總是得到一些垃圾:"ÝÝÝÝ...ÝÝÝÝÝÝ"為了確認(rèn)是不是我的 CString 數(shù)據(jù)出了問(wèn)題,我試著用 GetBuffer,然后強(qiáng)制轉(zhuǎn)化成 char*,LPCSTR。GetBuffer 返回的值是正確的,但是當(dāng)我把它賦值給 char* 時(shí),它就變成垃圾了。以下是我的程序段:

char* szName = GetName().GetBuffer(20);

RegSetValueEx(hKey, "Name", 0, REG_SZ,

              (CONST BYTE *) szName,

              strlen (szName + 1));

這個(gè) Name 字符串的長(zhǎng)度小于 20,所以我不認(rèn)為是 GetBuffer 的參數(shù)的問(wèn)題。

真讓人困惑,請(qǐng)幫幫我。

親愛的 Frustrated,

你犯了一個(gè)相當(dāng)微妙的錯(cuò)誤,聰明反被聰明誤,正確的代碼應(yīng)該象下面這樣:

CString Name = GetName();

RegSetValueEx(hKey, _T("Name"), 0, REG_SZ,

                     (CONST BYTE *) (LPCTSTR)Name,

                     (Name.GetLength() + 1) * sizeof(TCHAR));

  為什么我寫的代碼能行而你寫的就有問(wèn)題呢?主要是因?yàn)楫?dāng)你調(diào)用 GetName 時(shí)返回的 CString 對(duì)象是一個(gè)臨時(shí)對(duì)象。參見:《C++ Reference manual》§12.2

  在一些環(huán)境中,編譯器有必要?jiǎng)?chuàng)建一個(gè)臨時(shí)對(duì)象,這樣引入臨時(shí)對(duì)象是依賴于實(shí)現(xiàn)的。如果編譯器引入的這個(gè)臨時(shí)對(duì)象所屬的類有構(gòu)造函數(shù)的話,編譯器要確保這個(gè)類的構(gòu)造函數(shù)被調(diào)用。同樣的,如果這個(gè)類聲明有析構(gòu)函數(shù)的話,也要保證這個(gè)臨時(shí)對(duì)象的析構(gòu)函數(shù)被調(diào)用。

  編譯器必須保證這個(gè)臨時(shí)對(duì)象被銷毀了。被銷毀的確切地點(diǎn)依賴于實(shí)現(xiàn).....這個(gè)析構(gòu)函數(shù)必須在退出創(chuàng)建該臨時(shí)對(duì)象的范圍之前被調(diào)用。

  大部分的編譯器是這樣設(shè)計(jì)的:在臨時(shí)對(duì)象被創(chuàng)建的代碼的下一個(gè)執(zhí)行步驟處隱含調(diào)用這個(gè)臨時(shí)對(duì)象的析構(gòu)函數(shù),實(shí)現(xiàn)起來(lái),一般都是在下一個(gè)分號(hào)處。因此,這個(gè) CString 對(duì)象在 GetBuffer 調(diào)用之后就被析構(gòu)了(順便提一句,你沒有理由給 GetBuffer 函數(shù)傳遞一個(gè)參數(shù),而且沒有使用ReleaseBuffer 也是不對(duì)的)。所以 GetBuffer 本來(lái)返回的是指向這個(gè)臨時(shí)對(duì)象中字符串的地址的指針,但是當(dāng)這個(gè)臨時(shí)對(duì)象被析構(gòu)后,這塊內(nèi)存就被釋放了。然后 MFC 的調(diào)試內(nèi)存分配器會(huì)重新為這塊內(nèi)存全部填上 0xDD,顯示出來(lái)剛好就是“Ý”符號(hào)。在這個(gè)時(shí)候你向注冊(cè)表中寫數(shù)據(jù),字符串的內(nèi)容當(dāng)然全被破壞了。

  我們不應(yīng)該立即把這個(gè)臨時(shí)對(duì)象轉(zhuǎn)化成 char* 類型,應(yīng)該先把它保存到一個(gè) CString 對(duì)象中,這意味著把臨時(shí)對(duì)象復(fù)制了一份,所以當(dāng)臨時(shí)的 CString 對(duì)象被析構(gòu)了之后,這個(gè) CString 對(duì)象中的值依然保存著。這個(gè)時(shí)候再向注冊(cè)表中寫數(shù)據(jù)就沒有問(wèn)題了。

  此外,我的代碼是具有 Unicode 意識(shí)的。那個(gè)操作注冊(cè)表的函數(shù)需要一個(gè)字節(jié)大小,使用lstrlen(Name+1) 得到的實(shí)際結(jié)果對(duì)于 Unicode 字符來(lái)說(shuō)比 ANSI 字符要小一半,而且它也不能從這個(gè)字符串的第二個(gè)字符起開始計(jì)算,也許你的本意是 lstrlen(Name) + 1(OK,我承認(rèn),我也犯了同樣的錯(cuò)誤?。?。不論如何,在 Unicode 模式下,所有的字符都是2個(gè)字節(jié)大小,我們需要處理這個(gè)問(wèn)題。微軟的文檔令人驚訝地對(duì)此保持緘默:REG_SZ 的值究竟是以字節(jié)計(jì)算還是以字符計(jì)算呢?我們假設(shè)它指的是以字節(jié)為單位計(jì)算,你需要對(duì)你的代碼做一些修改來(lái)計(jì)算這個(gè)字符串所含有的字節(jié)大小

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多