【问题标题】:sprintf and char [] vs. stringsprintf 和 char [] 与字符串
【发布时间】:2009-07-17 16:24:48
【问题描述】:

我需要将const char * 传递给函数。在我通过它之前,我通常需要从一些变量中构建它。我永远无法决定哪种方法更优雅,整体更好:

  • 分配一个足够长的数组以容纳文本并使用sprintf 构建最终变量并将其传递给函数。
  • 使用 + 运算符(连接)使用变量初始化字符串 s,然后使用 s.c_str() 将其传递给函数。

使用数组的缺点:可能不适合整个文本。
优点:快。

使用字符串的缺点:我不需要担心内存管理,易于构建。 优点:慢。

我的第二个问题是:你通常如何从其他变量字符串构建一个完整的字符串?

【问题讨论】:

  • 不是骗子,但也许值得一试:stackoverflow.com/questions/445315/…
  • 即使有理由使用纯 C 方法,也请不要使用 sprintf() - 改用 snprintf()。
  • 我不认为 sprintf/snprintf 是最有效的,毕竟它必须解析格式化字符串,但它确实比大部分 c++ 方法在语法上更清晰。老实说,C 和 C++ 中的标准字符串操作在优雅和效率方面都需要做一些工作。

标签: c++ c


【解决方案1】:

除非它绝对对性能至关重要,否则我倾向于使用 std::stringstream 从其组件构建字符串,然后使用 c_str() 生成字符串。这是安全的,因为这种方式实际上不会发生缓冲区溢出,而且通常足够快。

如果分析器告诉我构建字符串是一个热点,那么您将不得不牺牲一些安全性来换取速度并开始使用类似 sprintf 的东西,但我宁愿避免这种情况。总的来说,我会将此作为最后的手段。

【讨论】:

  • 您不必以安全为代价,因为您可以使用 snprintf 代替 sprintf。
  • snprintf 仍然非常不安全,即使缓冲区溢出没有问题。坚持使用 stringstream,或者至少是 string。如果在分析代码后发现这是一个瓶颈,则可以稍后进行优化。
  • snprintf 不安全。当然,它可以防止缓冲区溢出,但它不能确保类型安全。
  • snprintf 应该避免,因为你很容易遇到一个错误(在某些情况下可以被利用)。改用 snprintf_s
【解决方案2】:

这听起来确实像是 Herb Sutter 的优秀文章 The String Formatters of Manor Farm 的一个案例。

记录一下:我自己使用std::ostringstream,构建字符串并传递oss.str().c_str()

【讨论】:

    【解决方案3】:

    缓冲区太短导致的崩溃将抵消您从 sprintf 获得的所有速度节省。无论如何,我不相信它会更快。即使是这样,差异是否足以令人担忧?

    【讨论】:

    • +1。使用 char 数组的唯一真正充分理由是,如果您正在使用 RealTime 系统并且需要该代码的确定性行为。
    【解决方案4】:

    由于内存管理更容易,我几乎总是使用stringstringstreamsprintf 和其他老式 C 库调用太容易出错了。

    sprintf 样式函数相对于stringstream 的一个好处是,它可以轻松地在运行时使用不同的格式字符串,以实现国际化。但是您绝对应该使用snprintf 或它的其他“更安全”的变体之一。

    【讨论】:

    • Boost 格式可以满足您的要求。
    【解决方案5】:

    谈到 C++ 和优雅,我倾向于遵循两条规则:

    1. 说出你的意思。
    2. 先配置,后优化。

    您在这里谈论的是连接字符串,所以这是我想到的代码:

    std::string s = s1 + s2 + s3 + s4;
    foo(s.c_str());
    

    为了“说出你的意思”,我联系了operator +。使用std::stringstream(字符串流)也很好,但我不会立即使用另一个#include 来连接字符串。我想这是个人喜好的问题。我绝对不会考虑手动构建一个原始的 char 数组。

    就性能而言,我的猜测是operator + 可能是最慢的组合字符串的方法。但即使是缓慢的方法也可能足以满足您的目的。

    【讨论】:

      【解决方案6】:

      每天早上醒来时对自己重复三遍,每晚睡前重复三遍:

      “过早的优化是万恶之源。” - 克努特

      换句话说,采用安全、惯用的 C++ 方式。速度应该在(如果)成为问题时修复,而不是之前修复,特别是如果之前修复它会使您的代码更容易出错。

      至于你的第二个问题:查看ropes

      【讨论】:

      • 首先,您的报价不正确 - 检查 Knuth 所说的确切内容(关于百分比)。其次,也许这听起来像是异端邪说,但 Knuth 的这句话只不过是教条,尤其是在您推荐使用它的方式上。我认为这个教条弊大于利——程序员学会了不关心代码的性能。如果您怀疑某个地方会成为热点,请在设计阶段立即对其进行优化。这种方法对我来说从来没有失败过。最后一个 - 绳索对于需要良好的旧空终止字符串的人来说毫无用处。
      • @qrdl... 我想你是对的。 shreevatsa.wordpress.com/2008/05/16/…
      • 你知道,我也听说过“Script Kitties”,他们甚至从未考虑过阅读 Knuth 的名言。通常他们使用它来证明他们为什么使用脚本语言,甚至不证明他们的设计是合理的,并且作为一个借口,我总是告诉你在编写任何代码之前应该先做的事情......想想。摩尔定律无法克服以脚本语言编写、在语言 VM 上实现、在由 100 个客户端分时共享的虚拟 Linux 服务器上运行的低效设计软件。
      • @qrdl 我会查找 Knuth 的报价。这并不是说您不应该关心代码的性能。只是还有其他顾虑;类型安全、内存管理等;在这种情况和许多其他情况下应该优先考虑。逻辑很简单:当有其他损坏的东西盯着你看时,不要修复可能损坏的东西。至于绳索与绳索,绳索对于需要好的旧绳索的人来说毫无用处。你想说什么?每个都有它的用途。我建议使用绳索,因为绳索在连接时表现出色,这是他所问的。
      • @Pete Eddy 我不仅读过 Knuth 的计算机编程艺术卷。 1-3,但我在我的个人项目中编写了大量的 C/C++。请不要通过攻击那些不同意你的人来为你的立场辩护。这不是依赖摩尔定律,而是关于 K.I.S.S.当然,您不应该犯任何明显的设计错误(不要使用冒泡排序对十亿个条目进行排序!)。但也不要过度复杂化您的代码并牺牲类型安全来修复幻像性能问题。
      【解决方案7】:

      你没有提到你的平台,但如果你使用 glibc 作为你的标准库,有 GNU 扩展 - asprintf(),它会自动分配足够大的字符串。

      详情请见man asprintf

      更通用的方法 - 首先调用 fprintf() 到未使用的流只是为了获取返回的长度,然后分配字符串并打印到它,如下所示:

      FILE *stream = tmpfile();
      char *string;
      
      string = malloc(fprintf(stream, format, param)+1);
      sprintf(string, format, param);
      

      【讨论】:

      • 我需要一个多平台解决方案:Win32、solaris、AS3、AS4、AS5....有趣的功能
      猜你喜欢
      • 2019-11-20
      • 2018-06-30
      • 2010-12-05
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-25
      相关资源
      最近更新 更多