为什么在C++中使用C字符串?

20
现在在C++中使用C字符串有什么好的理由吗?我的教科书在某些地方使用它们作为示例,但我真的觉得使用std::string会更容易。
18个回答

23

我使用C风格字符串的唯一原因是与使用C风格字符串的第三方库进行接口交互。也可能会有一些神秘的情况需要出于性能的考虑使用C风格字符串,但更常见的是,由于内联和特化等原因,使用C++字符串上的方法可能更快。

在处理这些类型的API时,您可以在许多情况下使用c_str()方法,但您应该知道返回的char *是const的,并且您不应通过该指针修改字符串。在这种情况下,您仍然可以使用vector<char>,至少可以获得更轻松的内存管理优势。


5
返回值之所以是const,是有原因的。通过使用const_cast或C cast进行修改会使内部对象状态失同步。它应该是“不能修改”,而不是“不应该修改”。 - Thorsten79

15

还有一些与内存控制相关的注意事项:

C字符串是POD类型,所以它们可以在应用程序的只读数据段中分配。如果你在命名空间范围内声明并定义了std::string常量,编译器会生成额外的代码,在main()之前调用每个常量的std::string构造函数。如果你的应用程序有许多常量字符串(例如如果你生成使用常量字符串的C++代码),那么在这种情况下使用C字符串可能更好。

一些std::string的实现支持一种称为SSO("短字符串优化"或"小字符串优化")的特性,其中std::string类包含存储长度不超过某个值的字符串的存储空间。这增加了std::string的大小,但往往显著减少了自由存储区分配/释放的频率,从而提高了性能。如果你的std::string实现不支持SSO,则在堆栈上构造一个空的std::string仍将执行自由存储区分配。如果是这种情况,则对于使用字符串的性能关键代码,使用临时堆栈分配的C字符串可能会有帮助。当然,在这样做时要小心不要自己搬起石头砸自己的脚。


10
因为这些信息是从多个API/库获取的。

4

内存控制。最近我需要处理大约200-300 MB大小的字符串(实际上是来自数据库的二进制数据),在一个高度多线程的应用程序中。这种情况下,再复制一次字符串可能会使32位地址空间溢出。我必须确切地知道有多少个字符串副本存在。虽然我是STL的信奉者,但我使用了char *,因为它保证不会分配额外的内存或者进行额外的复制。我知道它需要多少空间。

除此之外,标准STL字符串处理还缺少了一些很棒的C函数用于字符串处理/解析。幸运的是,std::string有c_str()方法可以访问内部缓冲区。要使用printf(),你仍然需要使用char *(C++团队没有包含(s)printf类似的功能,这是一个多么疯狂的想法啊,这是C语言中最有用的函数之一。我希望boost::format很快会被包含在STL中。


1
有类似于sprintf的功能 - 你只需要使用字符串流和标准输出运算符。 - Branan
@Branan:是的,但这不是同一件事情,如果你需要很多参数,它会变得非常尴尬。 - Andreas Bonini

3
假设您的代码中有一些字符串常量,这是非常常见的需求。最好将它们定义为C字符串而不是C++对象--更轻量级,可移植等等。现在,如果您将这些字符串传递给各种函数,那么如果这些函数接受C字符串而不是要求C++字符串对象,则很好。
当然,如果字符串是可变的,则使用C++字符串对象更加方便。

3
请注意,接受C++字符串对象的相同函数将由于隐式构造函数而接受C字符串,因此没有必要保留这些函数。至于“更轻量级”和“更便携”,代价是需要使用指针(并且需要进行测试),这对我来说成本太高了... - paercebal
某些函数确实接受 C++ 字符串对象,但有些则不是。此外,隐式构造会带来性能开销。但是,是的,这存在一些权衡。 - adum

3
如果一个函数需要一个常量字符串,即使程序在其他地方使用std::string、CString、EString或其他东西,我仍然更喜欢使用'const char*'(或const wchar_t*)。
在大型代码库中,字符串的来源太多了,不能确定调用者是否将字符串作为std::string传递,而'const char*'是最低公共分母。

3

教科书上使用老派的C字符串,因为许多基本函数仍然期望它们作为参数或返回它们。此外,它可以让人们更深入了解内存中字符串的底层结构。


2

遗留代码不知道 std::string。此外,在 C++11 之前,使用 std::ifstream 或 std::ofstream 打开文件只能将 const char* 作为文件名的输入。


2

如果C++代码“深入”(靠近内核,严重依赖于C库等),您可能希望显式使用C字符串以避免大量转换到和从std::string中。或者,如果您正在与其他语言域(Python,Ruby等)进行接口交互,出于同样的原因,您可能会这样做。否则,请使用std::string。


2

如果可以选择,通常没有理由选择原始的 C 字符串(char*)而不是 C++ 字符串(std::string)。然而,通常你没有选择的余地。例如,std::fstream 的构造函数采用 C 字符串,出于历史原因。此外,C 库(你猜对了!)使用 C 字符串。

在你自己的 C++ 代码中,最好使用 std::string 并通过使用 std::stringc_str() 函数 根据需要提取对象的 C 字符串。


2
当然,你必须使用C风格的字符串来表示字符串字面值。 - dan04
@dan04 不一定。给定 void f(std::string s);,你可以使用 f("C string"); 调用该函数,因为 C 字符串可以隐式转换为 std::string - wilhelmtell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接