CString 全面用法与最佳实践(MFC / ATL / Win32 / 全版本 VC)

CString 全面用法与最佳实践(MFC / ATL / Win32 / 全版本 VC)

CString 是 Windows C++ 桌面开发中使用最广泛的字符串类之一,广泛存在于 MFC、ATL、Win32 封装层、COM 接口 中。即使在大量引入 std::string / std::wstring 的现代 C++ 项目中,CString 仍然具有不可替代的工程价值。

本文从 基础用法 → 高级接口 → 跨库协作 → 性能与陷阱 → 现代实践,系统总结 CString 的全部常用能力。


一、CString 体系结构概览

1. 类型层级

1
2
3
typedef CStringT<TCHAR, StrTraitMFC<TCHAR>> CString;
typedef CStringT<char, StrTraitMFC<char>> CStringA;
typedef CStringT<wchar_t, StrTraitMFC<wchar_t>> CStringW;

本质:CStringCStringT 的 typedef


2. 字符集关系

编译模式 CString 实际类型
Unicode CStringW
ANSI CStringA
1
2
3
4
5
#ifdef UNICODE
// CString == CStringW
#else
// CString == CStringA
#endif

3. 内存模型(核心特性)

  • 引用计数
  • 写时拷贝(Copy-On-Write)
  • 小字符串优化(部分实现)
1
2
3
CString a = _T("hello");
CString b = a; // 共享内存
b += _T("!"); // 触发拷贝

二、CString 创建与初始化(全方式)

1. 默认构造

1
CString s;

2. 字面量 / 指针

1
2
3
CString s1(_T("Hello"));
CString s2 = L"Unicode";
CString s3("ANSI");

3. 拷贝 / 移动(现代 VC)

1
2
3
CString a(_T("A"));
CString b(a); // 拷贝
CString c(std::move(a)); // 移动(VC++ 新版本支持)

4. 从字符数组

1
2
TCHAR buf[] = _T("Buffer");
CString s(buf);

5. 从单字符 / 重复字符

1
2
CString s(_T('A'));
CString s2(_T('*'), 10); // **********

三、CString 与数值互转(完整)

1. 数值 → CString

1
2
3
4
5
6
int i = 10;
double d = 3.14159;

CString s;
s.Format(_T("%d"), i);
s.Format(_T("%.3f"), d);

2. CString → 数值

1
2
int i = _ttoi(s);
double d = _ttof(s);

3. 安全替代(现代)

1
int i = std::stoi(std::wstring(s));

四、格式化(Format / AppendFormat)

1. Format

1
2
CString s;
s.Format(_T("ID=%d, Name=%s"), 1, _T("Tom"));

2. AppendFormat(推荐)

1
s.AppendFormat(_T(", Age=%d"), 18);

五、拼接 / 修改操作

1. 拼接

1
2
3
s += _T(" World");
s.Append(_T("!"));
s.AppendChar(_T('?'));

2. 插入 / 删除 / 替换

1
2
3
s.Insert(5, _T(","));
s.Delete(5, 1);
s.Replace(_T("old"), _T("new"));

六、长度 / 访问 / 遍历

1
2
3
4
5
6
7
int len = s.GetLength();
bool empty = s.IsEmpty();

for (int i = 0; i < len; ++i)
{
TCHAR ch = s[i];
}

七、比较与排序

1
2
3
s1 == s2;
s1.Compare(s2);
s1.CompareNoCase(s2);

八、查找与定位

1
2
3
s.Find(_T("abc"));
s.ReverseFind(_T('a'));
s.FindOneOf(_T("xyz"));

九、子串截取

1
2
3
s.Left(3);
s.Right(4);
s.Mid(2, 5);

十、大小写 / 规范化

1
2
3
s.MakeUpper();
s.MakeLower();
s.MakeReverse();

十一、Trim / 清理字符

1
2
3
4
s.Trim();
s.TrimLeft();
s.TrimRight();
s.Trim(_T(" \t\r\n"));

十二、CString 与 C 接口交互(重点)

1. CString → LPCTSTR

1
LPCTSTR psz = s;

2. GetBuffer / ReleaseBuffer(高风险)

1
2
3
TCHAR* p = s.GetBuffer(256);
_tcscpy(p, _T("abc"));
s.ReleaseBuffer();

⚠ 必须配对


3. 更安全的替代

1
2
CString s;
s.Format(_T("%s"), psz);

十三、与 STL 字符串互转

1. CString → std::wstring

1
std::wstring ws(s.GetString());

2. std::string → CString

1
CString s(str.c_str());

十四、在 STL 容器中使用

1
2
std::vector<CString> vec;
vec.emplace_back(_T("A"));

十五、MFC 控件 / UI 绑定

1
2
SetDlgItemText(IDC_EDIT1, s);
GetDlgItemText(IDC_EDIT1, s);

十六、路径 / 文件名操作

1
2
3
4
CString path = _T("C:\\Temp\\file.txt");
int pos = path.ReverseFind(_T('\\'));
CString dir = path.Left(pos);
CString file = path.Mid(pos + 1);

十七、性能优化与工程实践

1. 预分配

1
s.Preallocate(1024);

2. 避免循环中 Format

1
2
for (...)
s.Format(...);

1
2
3
s.Empty();
for (...)
s.AppendFormat(...);

十八、线程安全说明

  • CString 不是线程安全
  • 不同线程不能同时写同一个实例
  • 可安全跨线程读(只读)

十九、CString vs std::string(工程结论)

场景 推荐
MFC UI / WinAPI CString
纯业务逻辑 std::string
COM / BSTR CStringW

二十、常见陷阱汇总

陷阱 说明
GetBuffer 忘记 Release 内存破坏
ANSI / Unicode 混用 乱码
%s%S 混用 格式错误
CStringA → CString 编码丢失

二十一、最佳实践总结

工程建议:

  • UI / 系统接口层:CString
  • 核心逻辑层:std::string
  • 明确编码边界
  • 禁止随意 GetBuffer


CString 全面用法与最佳实践(MFC / ATL / Win32 / 全版本 VC)
https://www.psnow.sbs/2026/01/28/CString-全面用法与最佳实践(MFC-ATL-Win32-全版本-VC)/
作者
Psnow
发布于
2026年1月29日
许可协议