std::string::compare返回int:负数表示当前字符串字典序小,0表示相等,正数表示大;支持子串比较,参数顺序为s1(pos1,len1)与s2(pos2,len2),pos越界抛异常而len自动截断。

compare 函数的返回值含义必须记牢
std::string::compare 不返回布尔值,也不返回 -1/0/+1 的“标准比较结果”,它返回的是一个 int:小于 0 表示当前字符串字典序小,等于 0 表示相等,大于 0 表示当前字符串字典序大。这个设计直接继承自 C 的 strcmp,但容易误以为是 bool 或三态枚举。
常见错误写法:if (s1.compare(s2)) —— 这在相等时为 0(false),不等时非零(true),看似能用,但语义反直觉;更危险的是 if (s1.compare(s2) == 1),因为实际返回值可能是任意正数(如 32、-7),只保证符号有意义。
正确判断方式应为:
s1.compare(s2) →s1 (字典序)-
s1.compare(s2) == 0→s1 == s2 -
s1.compare(s2) > 0→s1 > s2
compare 支持子串比较,但参数顺序易错
compare 有多个重载,最常用的是全字符串比较 s1.compare(s2),但真正灵活的是带位置和长度的版本:s1.compare(pos1, len1, s2, pos2, len2)。注意:前两个参数属于调用者(s1),后三个才属于被比较对象(s2),不是对称的。
立即学习“C++免费学习笔记(深入)”;
例如:s1.compare(1, 3, s2, 0, 3) 表示 “取 s1 从下标 1 开始长 3 的子串,与 s2 从下标 0 开始长 3 的子串比较”。如果越界,len 会被自动截断(不会抛异常),但 pos 超出 size() 会触发 std::out_of_range。
实用场景:
- 忽略前缀比较:
path.compare(0, prefix.length(), prefix) == 0 - 比较文件扩展名:
filename.compare(filename.length()-4, 4, ".txt") == 0
和 operator
日常比较用 s1 或 s1 == s2 更简洁安全,但 compare 唯一不可替代的点是:**一次调用可同时获取大小关系,避免多次比较开销**。比如排序回调或自定义比较器中需要三路分支时:
auto cmp = s1.compare(s2);
if (cmp < 0) { /* s1 smaller */ }
else if (cmp == 0) { /* equal */ }
else { /* s1 larger */ }若用运算符,就得写 s1 、s1 == s2 两次(底层可能重复扫描字符串)。另外,compare 支持传入 C 风格字符串(const char*)和指定长度,而运算符重载不支持长度限制,遇到嵌入 \0 的字符串会提前截断。
性能提示:所有 compare 重载都是 O(min(len)) 时间,且短路(遇到第一个不同字符就停),无需担心效率问题。
中文、UTF-8 字符串用 compare 会出问题吗?
会,而且很隐蔽。std::string::compare 是纯字节比较,不识别 UTF-8 编码规则。比如两个中文字符 "你好" 和 "好你",按字节比较结果取决于每个汉字的 UTF-8 编码字节序列(通常是 3 字节),完全不反映 Unicode 码点顺序或语言学意义上的“字典序”。
这意味着:
- 用
compare对含中文、emoji 或混合编码的字符串排序,结果不可预测 - 即使所有字符串都合法 UTF-8,
compare也只做二进制比较,不是 Unicode collation - 没有编译错误或运行时异常,错误只在业务逻辑中暴露(比如搜索不命中、列表乱序)
真要处理国际化文本,必须用 ICU 库或 C++20 的 std::locale + std::collate,而不是依赖 string::compare。










