好的C字符串库

时间:2011-01-14 04:41:29

标签: c string search io

我最近受到启发,启动了一个我想要编写代码的项目。我想在C中做,因为内存处理是这个应用程序的关键。我正在四处寻找C中字符串的良好实现,因为我知道我自己这样做会导致一些混乱的缓冲区溢出,而且我希望处理相当多的字符串。

我发现this文章详细介绍了每一个,但他们每个人都觉得他们有很多利弊(不要误解我的意思,这篇文章非常有帮助,但它仍然令人担忧我,即使我选择其中之一,我也不会使用我能得到的最好的)。我也不知道这篇文章是如何更新的,因此我目前的请求。

我正在寻找的东西可能包含大量字符,并简化了搜索字符串的过程。如果它允许我以任何方式标记字符串,甚至更好。此外,它应该有一些非常好的I / O性能。打印和格式化打印不是最重要的。我知道我不应该指望一个库为我做所有的工作,但只是在那里有一个记录良好的字符串函数,这可以节省我一些时间和一些工作。

非常感谢任何帮助。提前谢谢!

编辑:我被问及我喜欢的许可证。任何类型的开源许可都可以,但最好是GPL(v2或v3)。

EDIt2:我找到了betterString(bstring)库,它看起来很不错。良好的文档,小而多功能的功能,并且易于与c字符串混合。有没有关于它的好故事?我读到的唯一缺点是它缺乏Unicode(再次,读到这个,还没有看到它面对面),但其他一切似乎都很好。

EDIT3:另外,最好是纯C。

6 个答案:

答案 0 :(得分:27)

这是一个老问题,我希望你已经找到了一个有用的问题。如果您没有,请查看github上的简单动态字符串库。我在这里复制并粘贴作者的描述:

SDS是C的字符串库,旨在增强有限的libc字符串 通过添加堆分配的字符串来处理功能:

  • 使用起来更简单。
  • 二元安全。
  • 计算效率更高。
  • 但是......与普通的C字符串函数兼容。

这是使用替代设计而不是使用C来实现的 表示字符串的结构,我们使用存储的二进制前缀 在指向SDS返回给用户的字符串的实际指针之前。

+--------+-------------------------------+-----------+
| Header | Binary safe C alike string... | Null term |
+--------+-------------------------------+-----------+
         |
         `-> Pointer returned to the user.

由于在实际返回指针之前存储的元数据作为前缀, 并且因为每个SDS字符串隐含地在末尾添加一个空术语 字符串无论字符串的实际内容如何,​​SDS字符串都有效 与C字符串一起使用,用户可以互换使用它们 使用只读函数以只读方式访问字符串。

答案 1 :(得分:9)

我建议不要使用除mallocfreestrlenmemcpysnprintf之外的任何库。这些函数为您提供了在C语言中进行强大,安全和高效字符串处理的所有工具。只需远离strcpystrcatstrncpystrncat,其中往往会导致效率低下和可利用的漏洞。

由于您提到了搜索,无论您选择哪种库,strchrstrstr几乎肯定会成为您想要使用的库。 strspnstrcspn也很有用。

答案 2 :(得分:2)

如果你真的想从头开始做到这一点,你应该看看ICU,即Unicode支持,除非你确定你的字符串永远不会包含任何东西,只有普通的ASCII- 7 ...搜索,正则表达式,标记化都在那里。

当然,使用C ++可以使更多更容易,但即便如此,我对ICU的建议仍然有效。

答案 3 :(得分:2)

请检查milkstrings
示例代码:

int main(int argc, char * argv[]) {
  tXt s = "123,456,789" ;
  s = txtReplace(s,"123","321") ; // replace 123 by 321
  int num = atoi(txtEat(&s,',')) ; // pick the first number
  printf("num = %d s = %s \n",num,s) ;
  s = txtPrintf("%s,%d",s,num) ; // printf in new string
  printf("num = %d s = %s \n",num,s) ;
  s = txtConcat(s,"<-->",txtFlip(s),NULL) ; // concatenate some strings
  num = txtPos(s,"987") ; // find position of substring
  printf("num = %d s = %s \n",num,s) ;
  if (txtAnyError()) { //check for errors
    printf("%s\n",txtLastError()) ;
    return 1 ; }
  return 0 ;
  }

答案 4 :(得分:1)

我还发现需要一个外部C字符串库,因为我发现<string.h>函数非常低效,例如:

  • strcat()在性能上可能非常昂贵,因为每次连接字符串时都必须找到'\ 0'字符
  • strlen()价格昂贵,因为它必须找到'\ 0'字符而不是只读取维护的length变量
  • char数组当然不是动态的,可能会导致非常危险的错误(当你溢出缓冲区时,分段错误崩溃可能是个好方法)。

解决方案应该是一个不仅包含函数的库,还包含一个包装字符串的结构,它可以存储重要的字段,例如lengthbuffer-size

我通过网络查找了这些库,发现了以下内容:

  1. GLib字符串库(应该是最佳标准解决方案) - https://developer.gnome.org/glib/stable/glib-Strings.html
  2. http://locklessinc.com/articles/dynamic_cstrings/
  3. http://bstring.sourceforge.net/
  4. 享受

答案 5 :(得分:1)

我最近遇到了这个问题,需要附加一个包含数百万个字符的字符串。我最终做了自己的事。

它只是一个C字符数组,封装在一个跟踪数组大小和分配字节数的类中。

与SDS和std :: string相比,性能比基准

快10倍

https://github.com/pedro-vicente/table-string

基准

对于Visual Studio 2015,x86调试版本:

| API                   | Seconds           
| ----------------------|----| 
| SDS                   | 19 |  
| std::string           | 11 |  
| std::string (reserve) | 9  |  
| table_str_t           | 1  |  

clock_gettime_t timer;
const size_t nbr = 1000 * 1000 * 10;
const char* s = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
size_t len = strlen(s);
timer.start();
table_str_t table(nbr *len);
for (size_t idx = 0; idx < nbr; ++idx)
{
  table.add(s, len);
}
timer.now("end table");
timer.stop();

EDIT 通过在start(构造函数参数大小)分配字符串来实现最大性能。如果使用总大小的一小部分,性能会下降。 100分配的示例:

std::string benchmark append string of size 33, 10000000 times
end str:        11.0 seconds    11.0 total
std::string reserve benchmark append string of size 33, 10000000 times
end str reserve:        10.0 seconds    10.0 total
table string benchmark with pre-allocation of 330000000 elements
end table:      1.0 seconds     1.0 total
table string benchmark with pre-allocation of ONLY 3300000 elements, allocation is MADE 100 times...patience...
end table:      9.0 seconds     9.0 total