c++中如何转换大小写_c++字符串字母大小写转换函数【详解】

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

标准 C++ 没有直接提供「整串字符串大小写转换」的内置函数,std::string 本身不带 toUpper()toLowerCase() 成员函数。必须手动遍历 + 调用字符级转换函数,且要注意 locale 和 ASCII 边界问题。

std::toupper / std::tolower 逐字符转换(最常用)

这是最稳妥、跨平台、符合 C++ 标准的做法。但注意:std::toupperstd::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) 会导致未定义行为 —— 可能崩溃、输出乱码,或静默返回错误结果。

  • 错误示例:std::toupper('é') 在 Latin-1 环境下可能出错,因为 `'é'` 常被编码为 0xe9,即 -23
  • 正确做法永远先转 unsigned charstd::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::UnicodeStringboost::locale。标准库的 std::toupper 只保证 ASCII 字母可靠,这点必须刻进本能。