CString操作指南

來源:互聯網
上載者:User

 通過閱讀本文你可以學習如何有效地使用 CString。

  CString 是一種很有用的資料類型。它們很大程度上簡化了MFC中的許多操作,使得MFC在做字串操作的時候方便了很多。不管怎樣,使用CString有很多特殊的技巧,特別是對於純C背景下走出來的程式員來說有點難以學習。這篇文章就來討論這些技巧。
  使用CString可以讓你對字串的操作更加直截了當。這篇文章不是CString的完全手冊,但囊括了大部分常見基本問題。

這篇文章包括以下內容:

CString 對象的串連

格式化字串(包括 int 型轉化為 CString )
CString 型轉化成 int 型
CString 型和 char* 類型的相互轉化

char* 轉化成 CString
CString 轉化成 char* 之一:使用LPCTSTR強制轉化——基於內部是的LPCTSTR實現
CString 轉化成 char* 之二:使用CString對象的GetBuffer方法
CString 轉化成 char* 之三: 和控制項的介面
CString 型轉化成 BSTR 型;
BSTR 型轉化成 CString 型;
VARIANT 型轉化成 CString 型;    —— 用於COM技術中

載入字串表資源;
CString 和臨時對象;
CString 的效率;

總結

下面我分別討論。

1、CString 對象的串連

  能體現出 CString 類型方便性特點的一個方面就字串的串連,使用 CString 類型,你能很方便地串連兩個字串,正如下面的例子:

     CString gray(”Gray”);
     CString cat(”Cat”);
     CString graycat = gray + cat;

要比用下面的方法好得多:

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

2、格式化字串

  與其用 sprintf() 函數或 wsprintf() 函數來格式化一個字串,還不如用 CString 對象的Format()方法:
               CString s;
               s.Format(_T(”The total is %d”), total);
  用這種方法的好處是你不用擔心用來存放格式化後資料的緩衝區是否足夠大,這些工作由CString類替你完成。
  格式化是一種把其它不是字串類型的資料轉化為CString類型的最常用技巧,比如,把一個整數轉化成CString類型,可用如下方法:
            CString s;
            s.Format(_T(”%d”), total);
  我總是對我的字串使用_T()宏,這是為了讓My Code至少有Unicode的意識,當然,關於Unicode的話題不在這篇文章的討論範圍。
    _T()宏在8位字元環境下是如下定義的:
#define _T(x) x // 非Unicode版本(non-Unicode version)
而在Unicode環境下是如下定義的:
#define _T(x) L##x // Unicode版本(Unicode version)
所以在Unicode環境下,它的效果就相當於:
s.Format(L”%d”, total);
  如果你認為你的程式可能在Unicode的環境下運行,那麼開始在意用 Unicode 編碼。比如說,不要用 sizeof() 操作符來獲得字串的長度,因為在Unicode環境下就會有2倍的誤差。我們可以用一些方法來隱藏Unicode的一些細節,比如在我需要獲得字元長度的時候,我會用一個叫做DIM的宏,這個宏是在我的dim.h檔案中定義的,我會在我寫的所有程式中都包含這個檔案:
#define DIM(x) ( sizeof((x)) / sizeof((x)[0]) )
  這個宏不僅可以用來解決Unicode的字串長度的問題,也可以用在編譯時間定義的表格上,它可以獲得表格的項數,如下:
       class Whatever { … };
       Whatever data[] = { { … }, … { … },};
       for(int i = 0; i<DIM(data); i++)
       { /* vt */
         case VT_BSTR:
                     return CString(vaData->bstrVal);
         case VT_BSTR | VT_BYREF:
                    return CString(*vaData->pbstrVal);
         case VT_I4:
                    s.Format(_T("%d"), va->lVal);
                    return s;
         case VT_I4 | VT_BYREF:
                    s.Format(_T("%d"), *va->plVal);
                    return  s;
         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、載入字串表資源

  如果你想建立一個容易進行語言版本移植的應用程式,你就不能在你的原始碼中直接包含本土語言字串 (下面這些例子我用的語言都是英語,因為我的本土語是英語),比如下面這種寫法就很糟:
                 CString s = “There is an error”;
  你應該把你所有特定語言的字串單獨擺放(調試資訊、在發布版本中不出現的資訊除外)。這意味著向下面這樣寫比較好:
                 s.Format(_T(”%d - %s”), code, text);
  在你的程式中,文字字串不是語言敏感的。不管怎樣,你必須很小心,不要使用下面這樣的串:
                 // fmt is “Error in %s file %s”
                 // readorwrite is “reading” or “writing”
                 s.Format(fmt, readorwrite, filename);
  這是我的切身體會。在我的第一個國際化的應用程式中我犯了這個錯誤,儘管我懂德語,知道在德語的文法中動詞放在句子的最後面,我們的德國方面的發行人還是苦苦的抱怨他們不得不提取那些不可思議的德語錯誤提示資訊然後重新格式化以讓它們能正常工作。比較好的辦法(也是我現在使用的辦法)是使用兩個字串,一個用 於讀,一個用於寫,在使用時載入合適的版本,使得它們對字串參數是非敏感的。也就是說載入整個格式,而不是載入串“reading”,“writing”:

                // fmt is “Error in reading file %s”
                // “Error in writing file %s”
                s.Format(fmt, filename);
  一定要注意,如果你有好幾個地方需要替換,你一定要保證替換後句子的結構不會出現問題,比如在英語中,可以是主語-賓語,主語-謂語,動詞-賓語的結構等等。
  在這裡,我們並不討論 FormatMessage,其實它比 sprintf/Format 還要有優勢,但是不太容易和CString 結合使用。解決這種問題的辦法就是我們按照參數出現在參數表中的位置給參數取名字,這樣在你輸出的時候就不會把他們的位置排錯了。
  接下來我們討論我們這些獨立的字串放在什麼地方。我們可以把字串的值放入資源檔中的一個稱為 STRINGTABLE 的段中。過程如下:首先使用 Visual Studio 的資源編輯器建立一個字串,然後給每一個字串取一個ID,一般我們給它取名字都以 IDS_開頭。所以如果你有一個資訊,你可以建立一個字串資源然後取名為 IDS_READING_FILE,另外一個就取名為 IDS_WRITING_FILE。它們以下面的形式出現在你的 .rc 檔案中:

STRINGTABLEIDS_READING_FILE “Reading file %s”IDS_WRITING_FILE “Writing file %s”END
注意:這些資源都以 Unicode 的格式儲存,不管你是在什麼環境下編譯。他們在Win9x系統上也是以Unicode 的形式存在,雖然 Win9x 不能真正處理 Unicode。
然後你可以這樣使用這些資源:
// 在使用資源串表之前,程式是這樣寫的:
       CString fmt; 
        if(…)
              fmt = “Reading file %s”;
        else
              fmt = “Writing file %s”;
        … // much later 
        CString s; 
        s.Format(fmt, filename);
// 使用資源串表之後,程式這樣寫:
       CString fmt;
       if(…) 
             fmt.LoadString(IDS_READING_FILE);
       else
             fmt.LoadString(DS_WRITING_FILE); 
       … // much later  
       CString s; 
       s.Format(fmt, filename);
  現在,你的代碼可以移植到任何語言中去。LoadString 方法需要一個字串資源的 ID 作為參數,然後它從 STRINGTABLE 中取出它對應的字串,賦值給 CString 對象。 CString 對象的建構函式還有一個更加聰明的特徵可以簡化 STRINGTABLE 的使用。這個用法在 CString::CString 的文檔中沒有指出,但是在 建構函式的樣本程式中使用了。(為什麼這個特性沒有成為正式文檔的一部分,而是放在了一個例子中,我記不得了!)——【譯者註:從這句話看,作者可能是CString的設計者。其實前面還有一句類似的話。說他沒有對使用GetBuffer(0)獲得的指標指向的地址是否可讀做有效性檢查 】。這個特徵就是:如果你將一個字串資源的ID強制類型轉換為 LPCTSTR,將會隱含調用 LoadString。因此,下面兩個構造字串的例子具有相同的效果,而且其 ASSERT 在debug模式下不會被觸發:
        CString s;
        s.LoadString(IDS_WHATEVER);
        CString t( (LPCTSTR)IDS_WHATEVER );
        ASSERT(s == t);//不會被觸發,說明s和t是相同的。
  現在,你可能會想:這怎麼可能工作呢?我們怎麼能把 STRINGTABLE ID 轉化成一個指標呢?很簡單:所有的字串 ID 都在1~65535這個範圍內,也就是說,它所有的高位都是0,而我們在程式中所使用的指標是不可能小於65535的,因為程式的低 64K 記憶體永遠也不可能存在的,如果你試圖訪問0×00000000到0×0000FFFF之間的記憶體,將會引發一個記憶體越界錯誤。所以說1~65535的值不可能是一個記憶體位址,所以我們可以用這些值來作為字串資源的ID。
  我傾向於使用 MAKEINTRESOURCE 宏顯式地做這種轉換。我認為這樣可以讓代碼更加易於閱讀。這是個只適合在 MFC 中使用的標準宏。你要記住,大多數的方法即可以接受一個 UINT 型的參數,也可以接受一個 LPCTSTR 型的參數,這是依賴 C++ 的重載功能做到的。C++重載函數帶來的 弊端就是造成所有的強制類型轉化都需要顯示聲明。同樣,你也可以給很多種結構只傳遞一個資源名。

       CString s;
       s.LoadString(IDS_WHATEVER);
       CString t( MAKEINTRESOURCE(IDS_WHATEVER));
       ASSERT(s == t);
  告訴你吧:我不僅只是在這裡鼓吹,事實上我也是這麼做的。在My Code中,你幾乎不可能找到一個字串,當然,那些只是偶然在調試中出現的或者和語言無關的字串除外。

9、CString 和臨時對象

  這是出現在 microsoft.public.vc.mfc 新聞群組中的一個小問題,我簡單的提一下,這個問題是有個程式員需要往註冊表中寫入一個字串,他寫道:
  我試著用 RegSetValueEx() 設定一個註冊表鍵的值,但是它的結果總是令我困惑。當我用char[]聲明一個變數時它能正常工作,但是當我用 CString 的時候,總是得到一些垃圾:”ÝÝÝÝ…ÝÝÝÝÝÝ”為了確認是不是我的 CString 資料出了問題,我試著用 GetBuffer,然後強制轉化成 char*,LPCSTR。GetBuffer 返回的值是正確的,但是當我把它賦值給 char* 時,它就變成垃圾了。以下是我的程式段:

char* szName = GetName().GetBuffer(20);
RegSetValueEx(hKey, “Name”, 0, REG_SZ, (CONST BYTE *) szName, strlen (szName + 1));
這個 Name 字串的長度小於 20,所以我不認為是 GetBuffer 的參數的問題。

真讓人困惑,請幫幫我。

親愛的 Frustrated,

你犯了一個相當微妙的錯誤,聰明反被聰明誤,正確的代碼應該象下面這樣:

CString Name = GetName();
RegSetValueEx(hKey, _T(”Name”), 0, REG_SZ, (CONST BYTE *) (LPCTSTR)Name, (Name.GetLength() + 1) * sizeof(TCHAR));
  為什麼我寫的代碼能行而你寫的就有問題呢?主要是因為當你調用 GetName 時返回的 CString 對象是一個臨時對象。參見:《C++ Reference manual》§12.2
  在一些環境中,編譯器有必要建立一個臨時對象,這樣引入臨時對象是依賴於實現的。如果編譯器引入的這個臨時對象所屬的類有建構函式的話,編譯器要確保這個類的建構函式被調用。同樣的,如果這個類聲明有解構函式的話,也要保證這個臨時對象的解構函式被調用。
  編譯器必須保證這個臨時對象被銷毀了。被銷毀的確切地點依賴於實現…..這個解構函式必須在退出建立該臨時對象的範圍之前被調用。
  大部分的編譯器是這樣設計的:在臨時對象被建立的代碼的下一個執行步驟處隱含調用這個臨時對象的解構函式,實現起來,一般都是在下一個分號處。因此,這個 CString 對象在 GetBuffer 調用之後就被析構了(順便提一句,你沒有理由給 GetBuffer 函數傳遞一個參數,而且沒有使用ReleaseBuffer 也是不對的)。所以 GetBuffer 本來返回的是指向這個臨時對象中字串的地址的指標,但是當這個臨時對象被析構後,這塊記憶體就被釋放了。然後 MFC 的調試記憶體 Clerk會重新為這塊記憶體全部填上 0xDD,顯示出來剛好就是“Ý”符號。在這個時候你向註冊表中寫資料,字串的內容當然全被破壞了。
  我們不應該立即把這個臨時對象轉化成 char* 類型,應該先把它儲存到一個 CString 對象中,這意味著把臨時對象複製了一份,所以當臨時的 CString 對象被析構了之後,這個 CString 對象中的值依然儲存著。這個時候再向註冊表中寫資料就沒有問題了。
  此外,My Code是具有 Unicode 意識的。那個操作註冊表的函數需要一個位元組大小,使用lstrlen(Name+1) 得到的實際結果對於 Unicode 字元來說比 ANSI 字元要小一半,而且它也不能從這個字串的第二個字元起開始計算,也許你的本意是 lstrlen(Name) + 1(OK,我承認,我也犯了同樣的錯誤!)。不論如何,在 Unicode 模式下,所有的字元都是2個位元組大小,我們需要處理這個問題。微軟的文檔令人驚訝地對此保持緘默:REG_SZ 的值究竟是以位元組計算還是以字元計算呢?我們假設它指的是以位元組為單位計算,你需要對你的代碼做一些修改來計算這個字串所含有的位元組大小。

10、CString 的效率

  CString 的一個問題是它確實掩藏了一些低效率的東西。從另外一個方面講,它也確實可以被實現得更加高效,你可能會說下面的代碼:
      CString s = SomeCString1;
      s += SomeCString2;
      s += SomeCString3;
      s += “,”;
      s += SomeCString4;
比起下面的代碼來,效率要低多了:

      char s[1024];
      lstrcpy(s, SomeString1);
      lstrcat(s, SomeString2);
      lstrcat(s, SomeString 3);
      lstrcat(s, “,”);
      lstrcat(s, SomeString4);
  總之,你可能會想,首先,它為 SomeCString1 分配一塊記憶體,然後把 SomeCString1 複製到裡面,然後發現它要做一個串連,則重新分配一塊新的足夠大的記憶體,大到能夠放下當前的字串加上SomeCString2,把內容複寫到這塊記憶體 ,然後把 SomeCString2 串連到後面,然後釋放第一塊記憶體,並把指標重新指向新記憶體。然後為每個字串重複這個過程。把這 4 個字串串連起來效率多低啊。事實上,在很多情況下根本就不需要複製源字串(在 += 操作符左邊的字串)。
  在 VC++6.0 中,Release 模式下,所有的 CString 中的緩衝都是按預定義量子分配的。所謂量子,即確定為 64、128、256 或者 512 位元組。這意味著除非字串非常長,連接字串的操作實際上就是 strcat 經過最佳化後的版本(因為它知道本地的字串應該在什麼地方結束,所以不需要尋找字串的結尾;只需要把記憶體中的資料拷貝到指定的地方即可)加上重新計算字串的長度。所以它的執行效率和純 C 的代碼是一樣的,但是它更容易寫、更容易維護和更容易理解。
  如果你還是不能確定究竟發生了怎樣的過程,請看看 CString 的原始碼,strcore.cpp,在你 vc98的安裝目錄的 mfc\src 子目錄中。看看 ConcatInPlace 方法,它被在所有的 += 操作符中調用。

啊哈!難道 CString 真的這麼”高效”嗎?比如,如果我建立

      CString cat(”Mew!”);
  然後我並不是得到了一個高效的、精簡的5個位元組大小的緩衝區(4個字元加一個結束字元),系統將給我分配64個位元組,而其中59個位元組都被浪費了。
  如果你也是這麼想的話,那麼就請準備好接受再教育吧。可能在某個地方某個人給你講過盡量使用少的空間是件好事情。不錯,這種說法的確正確,但是他忽略了事實中一個很重要的方面。
  如果你編寫的是運行在16K EPROMs下的嵌入式程式的話,你有理由盡量少使用空間,在這種環境下,它能使你的程式更健壯。但是在 500MHz, 256MB的機器上寫 Windows 程式,如果你還是這麼做,它只會比你認為的“低效”的代碼運行得更糟。
  舉例來說。字串的大小被認為是影響效率的首要因素,使字串儘可能小可以提高效率,反之則降低效率,這是大家一貫的想法。但是這種想法是不對的,精確的記憶體配置的後果要在程式運行了好幾個小時後才能體現得出來,那時,程式的堆中將充滿小片的記憶體,它們太小以至於不能用來做任何事,但是他們增加了你程式的記憶體用量,增加了記憶體頁面交換的次數,當頁面交換的次數增加到系統能夠忍受的上限,系統則會為你的程式分配更多的頁面,直到你的程式佔用了所有的可用記憶體。由此可見,雖然記憶體片段是決定效率的次要因素,但正是這些因素實際控制了系統的行為,最終,它損害了系統的可靠性,這是令人無法接受的。
  記住,在 debug 模式下,記憶體往往是精確分配的,這是為了更好的排錯。
  假設你的應用程式通常需要連續工作好幾個月。比如,我常開啟 VC++,Word,PowerPoint,Frontpage,Outlook Express,Forté Agent,Internet Explorer和其它的一些程式,而且通常不關閉它們。我曾經夜以繼日地連續用 PowerPoint 工作了好幾天(反之,如果你不幸不得不使用像 Adobe FrameMaker 這樣的程式的話,你將會體會到可靠性的重要;這個程式機會每天都要崩潰4~6次,每次都是因為用完了所有的空間並填滿我所有的交換頁面)。所以精確記憶體配置是不可取的,它會危及到系統的可靠性,並引起應用程式崩潰。
  按量子的倍數為字串分配記憶體,記憶體 Clerk就可以回收用過的記憶體塊,通常這些回收的記憶體塊馬上就可以被其它的 CString 對象重新用到,這樣就可以保證片段最少。分配器的功能加強了,應用程式用到的記憶體就能儘可能保持最小,這樣的程式就可以運行幾個星期或幾個月而不出現問題。
  題外話:很多年以前,我們在 CMU 寫一個互動式系統的時候,一些對記憶體 Clerk的研究顯示出它往往產生很多記憶體片段。Jim Mitchell,現在他在 Sun Microsystems 工作,那時侯他創造了一種記憶體 Clerk,它保留了一個記憶體配置狀況的運行時統計表,這種技術和當時的主流分配器所用的技術都不同,且較為領先。當一個記憶體塊需要被分割得比某一個值小的話,他並不分割它,因此可以避免產生太多小到什麼事都幹不了的記憶體片段。事實上他在記憶體 Clerk中使用了一個浮動指標,他認為:與其讓指令做長時間的存取記憶體操作,還不如簡單的忽略那些太小的記憶體塊而只做一些浮動指標的操作。(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.)他是對的。
  永遠不要認為所謂的“最佳化”是建立在每一行代碼都高速且節省記憶體的基礎上的,事實上,高速且節省記憶體應該是在一個應用程式的整體水平上考慮的。在軟體的整體水平上,只使用最小記憶體的字串分配策略可能是最糟糕的一種方法。
  如果你認為最佳化是你在每一行代碼上做的那些努力的話,你應該想一想:在每一行代碼中做的最佳化很少能真正起作用。你可以看我的另一篇關於最佳化問題的文章《Your Worst Enemy for some thought-provoking ideas》。
  記住,+= 運算子只是一種特例,如果你寫成下面這樣:

        CString s = SomeCString1 + SomeCString2 + SomeCString3 + “,” + SomeCString4;
則每一個 + 的應用會造成一個新的字串被建立和一次複製操作。

總結

  以上是使用 CString 的一些技巧。我每天寫程式的時候都會用到這些。CString 並不是一種很難使用的類,但是 MFC 沒有很明顯的指出這些特徵,需要你自己去探索、去發現。

下面是一些CString常用函數

CString常用函數
CString::CString(char *p)
{
int n=strlen(p);
m_data = new char[n+1];
strcpy(m_data,p);
}

CString::CString(CString &other)
{
int n=strlen(other.m_data);
m_data = new char[n+1];
strcpy(m_data,other.m_data);
}

CString::operator = (CString& other)  
// 在賦值之前並沒有考慮other與當前類對象是否為同一個類對象,因此是有隱患的。
{
delete[] m_data;
int n=strlen(other.m_data);
m_data = new char[n+1];
strcpy(m_data,other.m_data);
return *this;
}

String::~String()
{
delete [] m_data;
}

Collate,Compare
與一個字元長指標所指的字串進行比較,與strcmp相同,它們的區別是,分別調用_tcscoll,_tcsicmp。

Delete

int Delete( int nIndex, int nCount = 1 )

傳回值是被刪除前的字串的長度,nIndex是第一個被刪除的字元,nCount是一次刪除幾個字元。根據我實驗得出的結果:當nCount>字串的長度時會出錯,當nCount過大,沒有足夠的字元刪除時,此函數不執行。

FindOneOf

int FindOneOf( LPCTSTR lpszCharSet ) const;  // 從下面介紹知道,這是一個非常重要的功能。
此函數的功能是在尋找lpszCharSet中的任意一個字元,查到一個就把位置返回,沒有查到返回0。如:
CString str = “0123456789″;
int x = str.FindOneOf(”31″);

x的值是1。

Find

int Find( TCHAR ch ) const;

int Find( LPCTSTR lpszSub ) const;

int Find( TCHAR ch, int nStart ) const;

int Find( LPCTSTR pstr, int nStart ) const;

傳回值尋找到的序號,ch待搜尋的字元,lpszSub待搜尋的字元子串,nStart 從那裡開始搜尋。如:

CString str = “0123456789″;
int x = str.Find(”34″,4);

返回的值是-1.

GetAt

TCHAR GetAt( int nIndex ) const;

返回標號為nIndex的字元,你可以把字串理解為一個數組,GetAt類似於[].注意nIndex的範圍,如果不合適會有調試錯誤。

Insert

int Insert( int nIndex, TCHAR ch )
int Insert( int nIndex, LPCTSTR pstr )
返回修改後的長度,nIndex字元(或字串)插入後的標號。

Left
CString Left( int nCount ) const;

返回的字串的前nCount個字元。

Right與Left類似

MakeLower ,MakeUpper改變字元的大小寫

MakeReverse字元倒置,如:

CString str = “X0123456789″;

str.MakeReverse();

str變為”9876543210X”

+=

const CString& operator +=( const CString& string );
const CString& operator +=( TCHAR ch );
const CString& operator +=( LPCTSTR lpsz );

將參數合并到自己身上。

如: CString str = “0123456789″;

str+=”ha”;

str為”0123456789ha”;

str[]

TCHAR operator []( int nIndex ) const;

象處理字元數組一樣處理字串。

注意是唯讀。

CString str = “0123456789″;

str[0]=’x';

是錯誤的。

TrimLeft,TrimRight   // 預設從左邊或右邊去除space,table,newline等標記符號
void TrimLeft( );
void CString::TrimLeft( TCHAR chTarget );
void CString::TrimLeft( LPCTSTR lpszTargets );
void TrimRight( );
void CString::TrimRight( TCHAR chTarget );
void CString::TrimRight( LPCTSTR lpszTargets );
CString str = “\n\t a”;
str.TrimLeft();
str為“a”;

如果沒有參數,從左刪除字元(\n\t空格等),至到遇到一個非此類字元.

當然你也可以指定刪除那些字元.

如果指定的參數是字串,那麼遇上其中的一個字元就刪除.

CString str = “abbcadbabcadb “;

str.TrimLeft(”ab”);

結果”cadbabcadb ”

int CString::Remove( TCHAR ch );

ch刪除的字元.

返回刪除字元的個數,有多個時都會刪除.

CString 與char []之間的轉換.

     char str[100] = ”str”;
     CString sstr = “sstr”;
     sstr.Format(“%s”,str);
     str = LPCTSTR sstr;
     strcpy(str,(LPCTSTR)sstr);

如果是賦值,則要:
     CString s(_T(”This is a test “));
     LPTSTR p = s.GetBuffer();
     // 在這裡添加使用p的代碼
     if(p != NULL)    // 採用GetBuffer擷取的地址後,可以直接使用!
           *p = _T('');
     s.ReleaseBuffer();
     // 使用完後及時釋放,以便能使用其它的CString成員函數

str的值變了.

將NULL位元組放入CString中
1,   CString str("abc""def", 7);
      str +="g";
      int nLength = str.GetLength();
      nLength為8.
2,   CString str(”My name is hedan!”);
      str.SetAt(5, 0);
      int nLength = str.GetLength();
注意:不是所有的CString成員函數都可以,在使用時一定要小心。

執行個體:動態配置資料來源
       CString strDsn,strDBQ;
       strDsn = "DSN=test";
       strDBQ.Format( "DBQ=%s", strSourceMDBName);
       CString strConnect = strDsn + " " + strDBQ
       strConnect.SetAt(strDsn.GetLength(), '' );  //最後一個NULL字元,一般串連採用;作為分隔字元的       SQLConfigDataSource(NULL, ODBC_ADD_SYS_DSN, “Microsoft Access Driver (*.mdb)”, strConnect);

ubunoon

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.