12

我已经阅读了许多帖子,询问如何将 C++ 转换std::stringconst std::string&achar*以将其传递给 C 函数的问题,并且似乎有很多关于这样做的警告。必须注意字符串是连续的以及许多其他事情。关键是我从来没有真正理解所有需要注意的点,为什么

我想知道是否有人可以总结从 astd::string到 a的转换char*需要传递给 C 函数的注意事项和缺点?

std::string是一个const引用并且它只是一个非常量引用时,以及 C 函数何时会改变char*以及何时不会改变它。

4

5 回答 5

11

首先,无论是 const 引用还是 value 都不会改变任何东西。

然后,您必须考虑函数的期望。一个函数可以用 achar*或 a做不同的事情char const*——例如,原始版本memcpy使用了这些类型,并且可能仍然存在这样的代码。希望它很少见,在下文中,我将假设char*C 函数中的 引用'\0' 终止的字符串。

如果 C 函数采用,则可以将;char const*的结果传递给它 std::string::c_str()如果需要 a char*,则取决于。如果它char*只是因为它可以追溯到constC 的早期,而实际上它没有修改任何内容,那么在 std::string::c_str()后面加上 aconst_cast是合适的。但是,如果 C 函数将char*用作输出参数,事情就会变得更加困难。我个人更喜欢声明一个缓冲区 ,传递它,char[]然后将结果转换为之后将字符串重新调整为结果长度(使用确定std::stringstd::stringstd::stringstd::string::resize()&s[0]strlen(s.c_str()),如有必要)也可以使用。

最后(但这也是使用 C 程序的问题 char[]),您必须考虑任何生命周期问题。大多数函数采用char*char const*简单地使用指针,然后忘记它,但如果函数将指针保存在某处以供以后使用,则字符串对象必须至少存在一样长的时间,并且在此期间不应修改其大小。(同样,在这种情况下,我更喜欢使用char[].)

于 2011-04-12T08:59:24.593 回答
6

基本上,有三点很重要:

  • 根据目前的标准,std::string实际上并不能保证使用连续存储(据我所知这是由于变化)。但事实上,所有当前的实现都可能无论如何都使用连续存储。因此,c_str()(and data()) 实际上可能会在内部创建字符串的副本……</p>

  • c_str()(and )返回的指针data()只有在没有调用原始字符串的非常量方法时才有效。这使得它在 C 函数挂在指针上时不适合使用(而不是仅在实际函数调用期间使用它)。

  • 如果字符串有任何可能被修改,那么放弃 constnessc_str()并不是一个好主意。您必须使用字符串的副本创建一个缓冲区,并将其传递给 C 函数。如果创建缓冲区,请记住添加空终止。

于 2011-04-12T08:53:24.110 回答
4

[我会添加评论,但我没有足够的代表,所以很抱歉添加(还)另一个答案。]

虽然当前标准确实不能保证 std::string 的内部缓冲区是连续的,但似乎几乎所有实现都使用连续缓冲区。此外,新的 C++0x 标准(即将获得 ISO 批准)需要 std::string 中的连续内部缓冲区,甚至当前的 C++03 标准在调用 data() 或&str[0] (虽然它不一定是空终止的)。有关更多详细信息,请参见此处

但这仍然不能保证写入字符串的安全,因为标准不会强制实现在调用 data()、c_str() 或运算符时实际返回其内部缓冲区,也不会阻止它们使用优化就像写时复制一样,这可能会使事情进一步复杂化(但似乎新的 C++0x 将禁止禁止写时复制)。话虽如此,如果您不关心最大的可移植性,您可以检查您的目标实现并查看它在内部实际做了什么。AFAIK,Visual C++ 2008/2010 总是返回真正的内部缓冲区指针,并且不执行写时复制(它确实有小字符串优化,但这可能不是问题)。

于 2011-04-12T09:41:14.910 回答
2

当 C 函数不改变后面的字符串时char*,您可以std::string::c_str()用于 const 和非常量std::string实例。理想情况下,它应该是const char*. 但如果不是(由于遗留 API),您可以合法地使用const_cast. c_str()但是,只要您不修改字符串,您就可以只使用指针!

当 C 函数确实更改了 后面的字符串时char*,使用 的唯一安全且可移植的方法std::string是自己将其复制到临时缓冲区(例如 from c_str())!确保之后释放临时内存 - 或使用std::vector,这保证有连续的内存。

于 2011-04-12T08:52:26.827 回答
1
  1. std:string 可以存储零字节。这意味着当传递给 C 函数时,它可能会被提前截断,因为 C 函数将在第一个零字节处停止。如果您尝试使用 C 函数过滤或转义不需要的字符,这可能会产生安全隐患。

  2. std::string::c_str() 的结果有时会因更改字符串的操作(非常量成员函数)而无效。如果您在第一次使用 c_str() 然后修改字符串后尝试使用此指针,将导致非常难以诊断错误(“Heisenbugs”)。

  3. 永远不要使用const_castgoto不那么麻烦。

于 2011-04-12T09:17:09.340 回答