std::toupper 直接传 char 会触发未定义行为,因为其要求参数为 unsigned char 范围内值或 EOF,而 signed char 的负值(如 UTF-8 高字节)传入即 UB;正确做法是先强转为 unsigned char 再调用。

直接用 std::transform 配合 std::toupper/std::tolower 最快,但必须注意 locale 和 char 符号性问题,否则在某些平台(如 Linux GCC)会触发未定义行为。
为什么 std::toupper 直接传 char 会崩?
因为 std::toupper(int c) 要求输入在 unsigned char 范围内或为 EOF。而 char 在多数编译器默认是 signed,遇到字节值 >127(比如 UTF-8 中文、带重音字母)时会变成负数,传进去就 UB。
- 错误写法:
std::transform(s.begin(), s.end(), s.begin(), ::toupper)——::toupper是 C 版本,不检查符号性 - 正确做法:先强转为
unsigned char,再进函数 - 更安全的选择:用
std::locale+std::use_facet,但开销大,日常 ASCII 场景没必要
最简可靠的大小写互换实现
用 lambda 封装转换逻辑,显式处理符号性,同时兼容大小写翻转(不是单纯转大写或小写):
std::string s = "Hello, 世界! 123";
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) -> char {
if (std::islower(c)) return std::toupper(c);
if (std::isupper(c)) return std::tolower(c);
return c; // 数字、标点、非 ASCII 字符原样保留
});
- lambda 参数必须是
unsigned char,避免负值传入std::islower等函数 - 返回类型写
char是为了匹配 string 的 value_type;C++11 起允许隐式转换 -
std::islower/std::isupper本身也要求unsigned char或EOF,所以前置强转必不可少
如果字符串含 UTF-8 多字节字符怎么办?
std::transform 按字节操作,对 UTF-8 无效 —— 它会把一个中文字符(如 "世" 的 UTF-8 编码是 0xE4 0xB8 0x96)拆成三个字节分别处理,结果完全不可读。
立即学习“C++免费学习笔记(深入)”;
- 纯 ASCII 文本(英文+数字+基本符号):上述方案完全够用
- 需要真正支持 Unicode:别用
std::string存 UTF-8 做大小写转换,改用std::u8string(C++20)或第三方库(如 ICU、utf8cpp) - 临时 workaround:只对 ASCII 字节范围(0–127)做变换,其余跳过 —— 上面的 lambda 已天然满足这点
最容易被忽略的是:哪怕你只处理英文,只要编译器把 char 当 signed 用(GCC/Clang 默认如此),漏掉 unsigned char 强转就会在某些输入下静默出错或崩溃。这不是“偶尔有问题”,而是标准明确定义的未定义行为。


















