填坑日记:关于std::string::npos的坑

今天新开一个文章分类,名唤“填坑日记”。用于记录日常碰到的小坑,不注文序,不分语言。以前踩过的坑,如果哪天突然想起来,就补充进来。

坑的描述 使用std::string::npos出现出乎意料的情况
根本原因 无符号数赋负值
填坑进度 已解决

问题描述:

今天的坑由一段简单的代码引起。这段代码用于实现在字符串中查找指定串,替换成另一个指定串。

[cpp]
int iPos = std::string::npos;
while ((iPos = strResult.find(strReplaceFrom)) > std::string::npos)
{
strResult.replace(iPos, strReplaceFrom.length(), strReplaceTo);
}
[/cpp]

其中std::string::npos的定义如下(http://www.cplusplus.com/reference/string/string/npos/):

[cpp]
static const size_t npos = -1;
[/cpp]

明明find到了(iPos > -1),却进入不了循环体。费解不?

原因分析:

其实原因很简单。size_t是unsigned int的typedef,这个坑实际上是无符号数赋负值的老问题。对无符号数赋值-1,内存中表示为全1,即相当于赋unsigned int最大值。以下一段代码可以说明这个问题:

[cpp]
int i = INT_MAX;
unsigned int u = -1;
if(i > u)
{
printf("i is Larger than u");
}
else
{
printf("i is NOT Larger than u");
}
[/cpp]

注意下图中两个变量的值。

无符号数赋值负数

解决方案:

[cpp]
int iPos = std::string::npos;
while ((iPos = strResult.find(strReplaceFrom)) > (int)std::string::npos)
{
strResult.replace(iPos, strReplaceFrom.length(), strReplaceTo);
}
[/cpp]

或者直接将std::string::npos替换成-1。

二零二零年二月七日

顾毅写于厦门