标准C++无内置字符串大小写转换函数,需手动遍历并用std::toupper/tolower逐字符转换,且必须将char先转为unsigned char以避免未定义行为。

标准 C++ 没有直接提供「整串字符串大小写转换」的内置函数,std::string 本身不带 toUpper() 或 toLowerCase() 成员函数。必须手动遍历 + 调用字符级转换函数,且要注意 locale 和 ASCII 边界问题。
用 std::toupper / std::tolower 逐字符转换(最常用)
这是最稳妥、跨平台、符合 C++ 标准的做法。但注意:std::toupper 和 std::tolower 参数是 int,且要求传入值能转为 unsigned char 或为 EOF,否则行为未定义 —— 这是绝大多数人踩坑的地方。
- 必须把
char先转成unsigned char再传给std::toupper,否则遇到负值(如 UTF-8 中的高位字节或某些 locale 下的扩展字符)会 UB - 只对属于
std::isalpha的字符做转换,数字、符号、空格等保持不变 - 默认按 "C" locale 工作,对非 ASCII 字符(如 `é`、`ß`、中文)无效;如需支持本地化,得传入显式
std::locale
std::string to_upper(const std::string& s) {
std::string result = s;
std::locale loc;
for (char& c : result) {
c = std::toupper(static_cast(c), loc);
}
return result;
}
std::transform + 函数对象(简洁写法)
比手写循环更泛型,也更常见于现代 C++ 代码中。关键仍是避免 char 符号问题,且不能直接用 std::toupper 函数指针 —— 因为重载歧义(它有带 locale 和不带 locale 两个版本)。
- 必须用 lambda 或显式绑定
std::locale,否则编译失败或调用错误重载 - 原地转换可直接作用于
str自身,无需额外拷贝(除非需要保留原串) - 性能和手写循环基本一致,无额外开销
std::string s = "Hello, 世界!";
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c) { return std::toupper(c); }); // 注意:这里仍只对 ASCII 安全
为什么不能直接用 std::toupper(c)(不加 static_cast)?
在有符号 char 平台上(如大多数 x86_64 Linux/GCC),如果字符串含非 ASCII 字节(例如 UTF-8 编码的 `中文`,首字节是 `0xe4`,作为 char 就是 `-28`),传给 std::toupper(-28) 会导致未定义行为 —— 可能崩溃、输出乱码,或静默返回错误结果。
立即学习“C++免费学习笔记(深入)”;
- 错误示例:
std::toupper('é')在 Latin-1 环境下可能出错,因为 `'é'` 常被编码为0xe9,即 -23 - 正确做法永远先转
unsigned char:std::toupper(static_cast(c)) - 若真要处理 Unicode,别用
std::toupper—— 改用 ICU、Boost.Locale 或手动查表
Windows 下 _strlwr / _strupr 能用吗?
可以,但不推荐。它们是 Microsoft 特有的 CRT 扩展函数,仅在 Windows + MSVC/MinGW-w64 下可用,且同样只处理单字节字符(即当前 code page,不是 UTF-8)。在 UTF-8 模式下传入中文会破坏编码,导致乱码甚至崩溃。
- 函数签名是
char* _strlwr(char*),会修改原串,不安全 - 没有 const 正确性,无法用于
const std::string& - 跨平台项目中混用会增加维护成本
真正需要大小写转换的复杂场景(比如国际化、Unicode 文本处理),别卡在标准库 —— 直接上 icu::UnicodeString 或 boost::locale。标准库的 std::toupper 只保证 ASCII 字母可靠,这点必须刻进本能。











