在库内部,我需要一个分配字符串的函数,将提供的浮点数写入带有%f格式的字符串,然后返回它。 snprintf()返回所需的字符数,这样我就可以通过2次snprintf()调用来分配正确的大小。不幸的是,这是一个有点性能关键的部分,所以我想避免这种情况,因为* printf()可能很慢(是的,在某些基准测试中,它确实出现在配置文件的#1处)。
另一种方法是使用一些C99函数来解决它,但libm调用也需要相当长的时间。我的函数的一个(非常简化,没有错误处理等)版本看起来像下面的
// Return a string containing number x in %f format with d digits after the decimal point.
char* my_function(double x, int d)
{
int n = ceil(log10(pow(2, ilogb(x))));
// 3 extra chars, the initial sign, the ".", and the terminating null.
char *s = malloc(n + d + 3);
snprintf(s, n + d+ 3, "%#-+.*f", d, x);
return s;
}
一种可能更快的方法是分配一个“足够大”的字符串,然后只在不太可能发生并且结果太短的情况下再进行第二次snprintf调用。
也可以构造代码,以便我可以使用alloca()和/或C99 VLA进行堆栈分配,但由于堆栈空间通常非常有限,我希望避免在最坏情况下浪费大量内存 - 大小合适的缓冲区。
有更好的主意吗?
答案 0 :(得分:1)
您是否在内存受限的系统中运行?如果你还没有真正需要计算字节数,那么只需确定最坏情况并将所有分配都调整为这个大小。
另一个选择是让调用者提供缓冲区。
最后,您是否知道您是否可以声明不需要同时存在超过有限数量的这些值?如果是这样,请为它们预先分配空间,不要在函数中执行malloc()。既然你说性能很关键,你应该试着避免使用malloc()。
答案 1 :(得分:1)
正如您在评论Find out field length of "%f" format in sprintf中所说:我希望快速使用常见案例,而“愚蠢”的案例(如%f格式,值非常大)更正。< /强>
这是一个解决方案:
char *function (double x, int d)
{
ssize_t ret;
size_t size = 32;
char *buffer = malloc(size);
ret = snprintf(buffer, size, "%#-+.*f", d, x);
if (ret < size) {
return buffer;
}
size = ret + 1;
buffer = realloc(buffer, size);
snprintf(buffer, size, "%#-+.*f", d, x);
return buffer;
}
32个字节是malloc()完成的最小分配的通用大小,请求较少不会给你任何东西。 您可以调整默认大小以匹配您要转换的公共值。
答案 2 :(得分:0)
您是否知道常见的malloc()实现不能分配少于32个字节。 所以你可能不应该关心字符串的确切大小。
如果你的程序是时间关键/或有内存限制,使用交换格式%a(%A),字符串的最大长度将非常小(-0x1.fffffffffffffp + 1023是最小负值)和使用预先分配的槽(使用专用的slab分配器)。