Borland string ::查找bug

时间:2013-04-13 13:50:50

标签: c++ string c++builder c++builder-5

我支持使用Borland C ++ Builder 5.02(从1997年)编写的C ++应用程序。 Borland字符串类中的find()方法不符合我的预期:

#include <cstring>
#include <iostream>

int main (int argc, char *argv[])
{
   string needle = "length == eighteen";
   string haystack = "<" + needle + ">";
   if (haystack.find(needle) != NPOS)
      cout << "Found it!" << endl;
   else
      cout << "Not found" << endl;

   return 0;
}

此程序输出Not found。如果我将针更换为更短的针,则输出Found it!。如果我为其他角色交换尖括号,则会找到它。空间有效,但括号也没有。

请注意,我在这里使用Borland字符串库:如果我#include <string>并使用std::string,那么它的工作方式与我的预期相符。遗憾的是,改变整个应用程序以使用STL字符串并不是一个可行的答案!

从文档中可以看出Borland使用基于散列的算法进行字符串搜索。我找不到更多有关这方面的细节,而且我已经完成了反汇编,但并不是更明智。

我发现很难相信这确实是字符串库中的一个错误,特别是因为如果是这样的话,我希望能够找到一篇关于它的文章或其他内容。我找不到任何此类信息。

然而,我已经没想完了!这是一个已知的错误?有修复吗?

编辑:再看一下反汇编,我认为它正在尝试做类似Rabin-Karp算法的事情,其中​​哈希函数计算为mod 33554393(最大素数&lt; 2 ^ 25)。它很可能是基数为32的多项式散列函数(即a_0 + 32 a_1 + 32 ^ 2 a_2 + .. + 32 ^ n a_n)但这只是一种预感。听起来丹尼尔费舍尔建议可能出现溢出。

3 个答案:

答案 0 :(得分:2)

我从1998年发现了一个引用,表明Borland的搜索字符串实现有一个错误:

https://groups.google.com/forum/?fromgroups=#!searchin/borland.public.cpp.language/cstring $ 20bug / borland.public.cpp.language / XBzjaJmCYpk / gtMPm-j8jugJ

此外,似乎在历史的某个时刻,C ++委员会认为字符串类是标准C ++的一部分,而cstring的字符串类是这个的残余:

https://groups.google.com/forum/?fromgroups=#!searchin/borland.public.cpp.language/borland $ 20cstring / borland.public.cpp.language / 2psY2seRmS4 / ywVrqwU1C2wJ

答案 1 :(得分:2)

如果您有原始的BC ++ 5.02安装盘,则可以在BC5 \ SOURCE \ RTL \ SOURCE \ STRING下找到字符串类源。

以下是string :: find_case_index()函数代码的摘录(由string :: find()调用):

const long q = 33554393L;
const long q32 = q<<5;

size_t testlength = length() - startindex;
size_t patternlength = patl = strlen(cp);
if( testlength < patternlength )
    return NPOS;
if( patternlength == 0 )
    return 0;

long patternHash = 0;
long testHash = 0;

const char _FAR *testP = c_str()+startindex;
const char _FAR *patP = cp;
long x = 1;
size_t i = patternlength-1;

while( i-- )
    x = (x<<5)%q;

for( i=0; i<patternlength; i++ )
    {
    patternHash = ( (patternHash<<5) + *patP++  ) % q;
    testHash    = ( (testHash   <<5) + *testP++ ) % q;
    }

testP = c_str()+startindex;
const char _FAR *end = testP + testlength - patternlength;

while (1)
    {

    if(testHash == patternHash)
        if( !get_paranoid_check_flag() ||
            !strncmp( testP, cp, patternlength) )
          return (size_t)(testP-c_str());

    if( testP >= end )
        break;

    // Advance & calculate the new hash value:
    testHash = ( testHash + q32 - *testP * x                 ) % q;
    testHash = ( (testHash<<5)  + *(patternlength + testP++) ) % q;
    }
return NPOS;          // Not found.

答案 2 :(得分:1)

您没有使用Borland字符串库。 String(大写S)是Borland字符串类。 string(小写s)与std::string完全相同,是STL字符串类,它不是Borland实现(BCB5中的STL是RogueWave STL)。您对#include <cstring>的使用可能会将std::string带入全局命名空间,这就是您的代码编译的原因。但您确实应该使用#include <string>std::string代替。对于NPOS,您应该使用string::npos,因为这是string::find()实际返回的内容。

#include <cstring>
#include <iostream>

int main (int argc, char *argv[])
{
   string needle = "length == eighteen";
   string haystack = "<" + needle + ">";
   if (haystack.find(needle) != string::npos)
      cout << "Found it!" << endl;
   else
      cout << "Not found" << endl;

   return 0;
}

或者:

#include <string>
#include <iostream>

int main (int argc, char *argv[])
{
   std::string needle = "length == eighteen";
   std::string haystack = "<" + needle + ">";
   if (haystack.find(needle) != std::string::npos)
      std::cout << "Found it!" << std::endl;
   else
      std::cout << "Not found" << std::endl;

   return 0;
}