必须用static_cast<unsigned char>转换再调toupper,否则char为负时toupper行为未定义;需先检查str.empty();C locale下toupper仅对a-z有效,Unicode大写需ICU等库。

直接修改 string 首字符:用 toupper + 下标访问
只要字符串非空,str[0] 就能安全访问首字符(C++11 起保证 data() 和 c_str() 非空时 operator[] 不越界),配合 std::toupper 即可完成转换:
if (!str.empty()) {
str[0] = std::toupper(static_cast<unsigned char>(str[0]));
}注意必须加 static_cast<unsigned char> ——std::toupper 对负值行为未定义,而 char 在某些平台默认有符号,读到高位为 1 的字节(如 UTF-8 中文首字节)会传入负数,导致未定义行为甚至崩溃。
为什么不能直接写 str[0] = toupper(str[0])
常见错误是漏掉类型转换,或用了 C 头文件里的 toupper(<ctype.h>)但没处理符号问题。以下是典型翻车点:
-
#include <ctype.h>后直接调toupper(str[0]):隐式 int 提升可能截断,且无符号保障 - 用
#include <cctype>但没 cast:char值 -64 传给int toupper(int),标准不保证结果 - 对空字符串调
str[0]:未检查empty(),触发未定义行为
只处理 ASCII 字母?还是想支持 locale?
std::toupper 默认按 “C locale” 工作,即只对 'a'–'z' 有效,其他字符(包括带重音的 é、ñ 或中文)原样返回。如果你需要法语、德语等本地化大写规则:
立即学习“C++免费学习笔记(深入)”;
- 用
std::use_facet<std::ctype<char>>(std::locale("fr_FR.UTF-8")).toupper(str[0]),但开销大,且需系统有对应 locale - 更实际的做法:先判断是否为 ASCII 小写字母(
'a' <= c && c <= 'z'),是则c - 'a' + 'A',否则跳过 —— 简单、快、无依赖 - 若真需 Unicode 大写(如 İ → İ、ß → SS),得用 ICU 或 Boost.Locale,
toupper完全不够用
性能与线程安全提醒
std::toupper 在 C locale 下通常是查表或位运算,非常快;但一旦切换 locale(比如全局 std::setlocale),它可能变成函数调用,且不是线程安全的 —— 多线程环境下,不同线程设不同 locale 会导致行为不可预测。
所以生产代码中,除非明确需要 locale 感知,否则优先用 ASCII 手动映射;如果必须用 std::toupper,确保:
- 始终使用
<cctype>而非<ctype.h> - 始终做
unsigned char强转 - 避免在多线程中动态切换 locale
最易被忽略的是那个 static_cast —— 它不改变逻辑,但决定了程序在含非 ASCII 字符的输入下是静默错还是当场崩。


















