【问题标题】:Borland string::find bugBorland string::find bug
【发布时间】:2013-04-05 23:50:19
【问题描述】:

我支持使用 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 &lt;string&gt; 并改用 std::string,那么它会完全按照我的预期工作。遗憾的是,将整个应用程序更改为使用 STL 字符串并不是一个可行的答案!

从文档看来,Borland 使用基于哈希的算法进行字符串搜索。我找不到更多关于这个的细节,我已经完成了反汇编,但并不聪明。

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

但是,我的想法已经用完了!这是一个已知的错误?有解决办法吗?

编辑:再次查看反汇编后,我认为它正在尝试执行类似 Rabin-Karp 算法的操作,其中哈希函数的计算方式为 mod 33554393(最大素数

【问题讨论】:

  • “基于哈希的算法”,“如果我把针改短一些”
  • 当您依赖 15 年的编译器时会发生这种情况。是时候继续前进了。
  • @PeterWood 在没有预算的情况下很难保持现状
  • @DavidHeffernan 这个问题是作为将这个(完全工作且非常有利可图的)系统迁移到更现代的编译器的项目的一部分而出现的。 “继续前进”是我们正在做的事情。但它必须像现在一样继续工作,pragmatictips.com/26 告诉我怀疑我自己对库错误的错误,因为前者的可能性更大。因此问题。
  • @DavidHeffernan 我不关心修复库。如果这是一个已知的库错误,那么我们可以证明更改应用程序以解决它(例如使用strstr())并迁移更改的代码是合理的。令我惊讶的是,我找不到任何证据表明这是一个已知的库错误。

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


【解决方案1】:

您没有使用 Borland 字符串库。 String(大写 S)是 Borland 字符串类。 string(小写 s)与 std::string 完全相同,是 STL 字符串类,它不是 Borland 实现(BCB5 中的 STL 是 RogueWave STL)。您对#include &lt;cstring&gt; 的使用可能会将std::string 带入全局命名空间,这就是您的代码编译的原因。但是您确实应该改用#include &lt;string&gt;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;
}

【讨论】:

  • 我不确定我们讨论的是同一个版本的类库。我在我的系统中找不到String 类,我使用的string 绝对不是std::string - 例如它有一个contains() 方法,而我的std::string 没有。类库文档肯定是关于 string 类的。你的两个程序都没有为我编译:第一个说undefined symbol 'npos',你的第二个说'cout' is not a member of 'std'。 [...待定]
  • [contd ...] 您说您安装了 BCB5 - 这是 5.02 还是免费提供的 5.5?你能编译并运行我给出的程序吗?如果可以,你看到相同的输出了吗?这将是最有帮助的。
  • @DaveTurner:我认为我们甚至不是在谈论同一个产品。您说您正在使用 Borland C++ Builder(这是我安装的),但我认为您实际上是在使用 Borland C++。它们不是相同的产品。在 Borland C++ 中,cstring.h 定义了一个非标准的 string 类,它不是 STL std::string 类。
  • @DaveTurner:Borland C++ Builder 使用 STL std::string 类,其 VCL 框架还定义了一个单独的 System::String 类,与 Delphi 二进制兼容。
【解决方案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

【讨论】:

    【解决方案3】:

    如果你有原始的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.
    

    【讨论】:

    • 谢谢,太棒了。我确定某处有一张安装 CD。我什至从未想过要寻找它的来源。
    • 如果您找到 CD 并决定尝试对源代码进行修复,请在此处查看如何构建 RTL 的说明以及对另一个错误的修复:jogy.net/bcrtlfix.html
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-03
    • 2016-10-25
    • 2012-04-23
    • 2012-02-06
    • 2018-12-19
    相关资源
    最近更新 更多