使用C风格的字符串有哪些缺点?

时间:2008-11-23 14:33:53

标签: c++ c string

我知道buffer overruns是使用C风格字符串(字符数组)的一个潜在危险。如果我知道我的数据适合我的缓冲区,是否可以使用它们?我还需要注意C风格字符串固有的其他缺点吗?

编辑:以下是我正在处理的示例:

char buffer[1024];
char * line = NULL;
while ((line = fgets(fp)) != NULL) { // this won't compile, but that's not the issue
    // parse one line of command output here.
}

此代码从使用popen("df")命令创建的FILE指针获取数据。我正在尝试运行Linux命令并解析其输出以获取有关操作系统的信息。将缓冲区设置为任意大小是否有任何错误(或危险)?

16 个答案:

答案 0 :(得分:20)

C字符串有一些缺点:

  1. 获取长度是一项相对昂贵的操作。
  2. 不允许使用嵌入的空字符。
  3. chars的签名是实现定义。
  4. 字符集是实现定义的。
  5. char类型的大小是实现定义的。
  6. 必须分别跟踪每个字符串的分配方式,以及如何将其分配,或者即使它根本需要免费提供。
  7. 无法将字符串切片称为另一个字符串。
  8. 字符串不是不可变的,这意味着它们必须单独同步。
  9. 在编译时无法操纵字符串。
  10. 切换案例不能是字符串。
  11. C预处理器无法识别表达式中的字符串。
  12. 无法将字符串作为模板参数传递(C ++)。

答案 1 :(得分:16)

C字符串缺少C ++对应的以下方面:

  • 自动内存管理:您必须手动分配和释放内存。
  • 连接效率的额外容量:C ++字符串的容量通常大于其大小。这样可以在不进行多次重新分配的情况下增加大小。
  • 没有嵌入式NUL:根据定义,NUL字符结束C字符串; C ++字符串保留一个内部大小计数器,因此它们不需要特殊值来标记它们的结尾。
  • 明智的比较和赋值运算符:即使允许比较C字符串指针,它几乎总是的意图。类似地,分配C字符串指针(或将它们传递给函数)会产生所有权歧义。

答案 2 :(得分:14)

在许多应用程序中,不能在恒定时间内访问长度是一个严重的开销。

答案 3 :(得分:8)

您可能知道,今天1024字节足以包含任何输入,但您不知道明天或明年情况会如何变化。

如果过早优化是所有邪恶的根源,那么神奇的数字就是干。

答案 4 :(得分:7)

如果需要,增加字符串(字符数组)所需的内存管理等对于重新发明来说有点无聊。

答案 5 :(得分:6)

无法将NUL字符(如果您需要它们)嵌入C样式字符串中。

答案 6 :(得分:6)

好吧,为了评论您的具体示例,您不知道调用df返回的数据是否适合您的缓冲区。永远不要相信未经过传真的输入到您的应用程序中,即使它被认为是来自像df这样的已知来源。

例如,如果名为“df”的程序放在搜索路径中的某个位置,以便执行它而不是系统df,则可以使用它来利用缓冲区限制。或者如果df被恶意程序替换。

从文件读取输入时,使用一个允许您指定要读取的最大字节数的函数。在OSX和Linux下,fgets()实际上定义为char *fgets(char *s, int size, FILE *stream);,因此在这些系统上使用是安全的。

答案 7 :(得分:3)

当你有一个字节数组而不是一串字符时,字符编码问题就会浮出水面。

答案 8 :(得分:3)

在您的特定情况下,不是c字符串是危险的,而是将不确定数量的数据读入固定大小的缓冲区。不要使用gets(char *)作为例子。

看一下你的例子,看起来似乎没有问题 - 试试这个:

char buffer[1024];
char * line = NULL;
while ((line = fgets(buffer, sizeof(buffer), fp)) != NULL) {
    // parse one line of command output here.
}

这是对c字符串的完全安全使用,尽管你必须处理line不包含整行的可能性,但是被截断为1023个字符(加上空终止符)

答案 9 :(得分:2)

我认为使用它们是可以的,人们多年来一直在使用它们。 但是如果可能的话我宁愿使用std :: string因为 1)你不必每次都这么谨慎,可以考虑你的域的问题,而不是认为你每次都需要添加另一个参数......内存管理和那种东西......它只是更安全更高层次的代码...... 2)可能还有一些其他的小问题并不重要但仍然......就像人们已经提到的那样......编码,unicode ......所有那些“相关”的东西人们创建std :: string的想法...... :)

<强>更新

我在一个项目上工作了半年。不知何故,我愚蠢到永远不会在发货前在发布模式下编译.... :) 嗯......幸运的是,我在3小时后发现了一个错误。 这是一个非常简单的字符串缓冲区溢出。

答案 10 :(得分:2)

现在没有Unicode支持是合理的......

答案 11 :(得分:0)

c字符串有滥用的机会,因为必须扫描字符串以确定其结束位置。

strlen - 查找长度,扫描字符串,直到您点击NUL,或访问受保护的内存

strcat - 必须扫描才能找到NUL,以确定从哪里开始连接。 c字符串中没有任何知识,无法判断是否存在缓冲区溢出。

c字符串存在风险,但通常比字符串对象快。

答案 12 :(得分:0)

Imho,cstrings最难处的是内存管理,因为如果你需要传递cstring的副本或者你可以将文字传递给函数,你需要小心,即。函数是否会释放传递的字符串,或者它会为函数调用保留更长的引用。这同样适用于cstring返回值。

因此,如果没有大的努力,就无法共享cstring copys。这在许多情况下以内存中相同cstring的不必要的复制结束。

答案 13 :(得分:0)

这个问题确实没有答案 如果你用C语写你有什么选择吗?
如果你用C ++写作,为什么要问?不使用C ++原语的原因是什么? 我能想到的唯一原因是:链接C和C ++代码并在接口中的某处使用char *。它有时候很容易使用char *而不是一直进行转换(特别是如果它真的'好'的C ++代码有3种不同的C ++字符串对象类型)。

答案 14 :(得分:0)

与C的许多其他方面一样,C字符串为您提供了充足的空间。它们简单快速,但在可能违反空终结符等假设或输入可能超出缓冲区的情况下不安全。为了可靠地完成它们,你必须观察相当的卫生编码实践。

曾经有一种说法,即高级语言的规范定义是“比C更好的字符串处理”。

答案 15 :(得分:0)

另一个考虑因素是谁将维护您的代码?两年后怎么样?那个人会像你一样对C-stlye琴弦感到舒服吗?随着STL变得越来越成熟,人们对STL字符串的使用感觉似乎比使用C风格的字符串更加舒适。