在 MFC 開發中,CString 是一個極為實用的字符串類,它大幅簡化了字符串操作。然而,對於習慣 C 風格字符串(char*)的開發者而言,CString 的內部機制與轉換技巧往往存在學習門檻。本文將系統梳理 CString 轉 char* 的多種方式、核心原理及常見陷阱,助你避開記憶體管理的雷區。
CString 內部重載了 LPCTSTR(本質是 const TCHAR*)轉換運算子,可直接返回內部緩衝區位址。這使得 CString 能隱式傳遞給要求 LPCTSTR 參數的函式:
CString s(_T("GrayCat"));
LPCTSTR p = s; // 隱式轉換,安全且高效
BOOL result = DoSomethingCool(s); // 直接傳遞 CString 實例
關鍵限制: 取得的指標指向 常量 緩衝區,嚴禁修改內容。嘗試寫入會導致編譯錯誤或運行時崩潰,因為 CString 內部維護著字符計數與緩衝區長度,外部修改會破壞其一致性,甚至導致緩衝區溢出。
當需要修改字符串內容(如截斷、替換字符)時,必須使用 GetBuffer() 獲取可寫指標(LPTSTR),操作完成後調用 ReleaseBuffer() 同步長度:
CString s(_T("File.ext"));
LPTSTR p = s.GetBuffer(); // 獲取可寫指標,預設不延長緩衝區
LPTSTR dot = _tcschr(p, _T('.'));
if (dot) *dot = _T('\0'); // 截斷副檔名
s.ReleaseBuffer(); // 重新計算長度,提交變更
若需擴充字符串(如 sprintf 格式化),可傳入預期長度:
LPTSTR p = s.GetBuffer(1024); // 確保至少 1024 字符空間
// ... 使用 p 進行寫入操作 ...
s.ReleaseBuffer(); // 自動更新實際長度
在兩者之間,CString 內部狀態處於不一致狀態,調用任何成員函式(如 GetLength()、TrimRight())皆屬未定義行為。
經典錯誤案例:
// 錯誤:GetName() 返回臨時 CString,GetBuffer() 後臨時對象隨即析構,緩衝區失效
char* szName = GetName().GetBuffer(20);
RegSetValueEx(hKey, "Name", 0, REG_SZ, (CONST BYTE*)szName, strlen(szName) + 1);
正確做法: 先拷貝至具名變量,延長生命週期:
CString name = GetName(); // 拷貝構造,持有數據所有權
RegSetValueEx(hKey, _T("Name"), 0, REG_SZ,
(CONST BYTE*)(LPCTSTR)name,
(name.GetLength() + 1) * sizeof(TCHAR));
此外,註冊表操作需注意 Unicode 環境下字節數計算(sizeof(TCHAR)),避免長度錯誤。
LPCTSTR 轉換,零成本、最安全。GetBuffer() / ReleaseBuffer(),嚴守「中間不碰 CString」鐵律。CString::Format(),避免手動緩衝區管理與 sprintf 的 Unicode 陷阱。GetBuffer(),務必先落地到變量。掌握這些規則,即可在 MFC 字符串處理中游刃有餘,徹底告別「野指標」與「緩衝區溢出」的噩夢。