【问题标题】:Estimate size of formatted snprintf() string?估计格式化的 snprintf() 字符串的大小?
【发布时间】:2014-02-18 19:30:47
【问题描述】:

我正在考虑编写一个函数来估计至少来自 sprintf()、snprintf() 函数的格式化字符串的全长。

我的方法是解析格式字符串以找到各种 %s、%d、%f、%p 参数,创建 strlen()s、itoa()s 和 strlen(format_string) 的运行总和以得到保证足够大的东西可以为 snprintf() 分配适当的缓冲区。

我知道以下工作,但它需要 10 倍的时间,因为所有 printf() 函数都非常灵活,但如果它的话,速度会很慢。

  char c;
  int required_buffer_size = snprintf(&c, 1, "format string", args...);

这已经完成了吗? - 通过建议的方法或其他一些相当有效的方法 - IE:比 sprintf() 变体快 5-50 倍?

【问题讨论】:

  • 花费“10 倍的时间”究竟是什么?您描述的功能必须再次实现 snprintf 才能正确,除非您愿意将其限制为格式说明符的子集......这是您想出更快替代方案的唯一方法。跨度>
  • @vanza,你能证明你的主张吗?我可以少做很多工作,比如使用长度为 12 的 int32_t、24 的 int64_t、80 的 %f 等。我已经有 5-10X 用于处理字符串。我会 RX 基准测试 snprintf()。所有 printf() 变体都非常慢。有时它们是唯一正确的解决方案,但这不是其中之一。
  • @JosephQuinsey,这正是我正在寻找的那种链接。非常感谢!!!
  • 注意:像“12 for an int32_t”这样的值是一个好方法。我发现char[sizeof(some_int_type)*3 + 3] 效果很好。但是%f 确实有一个令人讨厌的最坏情况。使用典型的双精度,大约 320 字节。当然——你可能已经知道了。

标签: c


【解决方案1】:

首先分配一个足够大的缓冲区并检查它是否足够长。如果不是重新分配并再次调用。

int len = 200;  /* Any number well chosen for the application to cover most cases */
int need;
char *buff = NULL; 
do {
  need = len+1;
  buff = realloc(buff, need);   /* I don't care for return value NULL */
  len = snprintf(buff, need, "...", ....);
  /* Error check for ret < 0 */
} while(len > need);
/* buff = realloc(buff, len+1); shrink memory block */

通过正确选择您的初始值,在大多数情况下,您只会调用一次snprintf(),并且一点点过度分配不应该是关键。如果您处于如此紧张的环境中,以至于这种过度分配至关重要,那么您已经在昂贵的分配和格式化方面遇到了其他问题。 在任何情况下,您仍然可以在之后调用realloc() 将分配的缓冲区缩小到确切的大小。

【讨论】:

  • 几乎是我现在使用的方法,除了我为 realloc() 定义了一个明确的步长。体面,但我认为在我的情况下,快速而肮脏的估计会更好。一个不错的调整是保持 max_size 因为在我的上下文中这是循环运行的。唯一需要注意的是,最大大小应该有一些限制,以防止由于缺少 nul 终止符或恶意字符串注入而导致大量分配。
  • 在这种情况下,基于解析格式字符串并调用strlen() 进行估计时,您将遇到同样的问题。在任何情况下,当构建处于时间关键循环中的字符串时;我更喜欢完全避免使用通用格式函数,并且只使用 O(1) 字符串连接,即没有 strcat()strlen()
  • 我不确定您所说的“仅使用 O(1) 字符串连接”是什么意思。你能详细谈谈?我猜你在谈论 Kamailio 风格 _str { char *p; int len;} “字符串”?我喜欢这种方法,但要避免在我扔在腿上的这个摇摇晃晃的旧系统上出现范围蔓延。
  • 是的,就是这样。使用和跟踪您处理的字符串的长度,避免使用 O(n) 函数 strcat()strlen() 等。它并不总是需要一个字符串类。它只需要在参数中传递长度,并有一个 concat 函数返回结果长度或指向末尾的指针。当然,这一切都取决于项目、平台和情况。
【解决方案2】:

如果snprintf 的第一个参数是NULL,则返回值是要写入的字符数。

【讨论】:

  • 太慢了。如..所示。 :(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-17
  • 1970-01-01
  • 2018-08-12
  • 1970-01-01
相关资源
最近更新 更多