如何在不知道函数的参数有多大的情况下,如何只分配真正需要的内存?
通常,我会使用固定大小,并计算其余部分sizeof(注意:代码不应该有意义,但要显示问题):
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
int test(const char* format, ...)
{
char* buffer;
int bufsize;
int status;
va_list arguments;
va_start(arguments, format);
bufsize = 1024; /* fixed size */
bufsize = sizeof(arguments) + sizeof(format) + 1024;
buffer = (char*)malloc(bufsize);
status = vsprintf(buffer, format, arguments);
fputs(buffer, stdout);
va_end(arguments);
return status;
}
int main()
{
const char* name = "World";
test("Hello, %s\n", name);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是,我不认为这是要走的路......所以,我如何在这里正确计算所需的缓冲区大小?
如果你vsnprintf有空,我会利用它.它可以防止缓冲区溢出,因为您提供了缓冲区大小,并返回所需的实际大小.
因此,分配您的1K缓冲区然后尝试使用vsnprintf写入缓冲区,限制大小.如果返回的大小小于或等于缓冲区大小,那么它可以工作,你可以只使用缓冲区.
如果返回的大小大于缓冲区大小,则调用realloc以获取更大的缓冲区并再次尝试.如果数据没有改变(例如,线程问题),第二个将正常工作,因为你已经知道它有多大.
如果您仔细选择默认缓冲区大小,这是相对有效的.如果您的绝大多数输出都在此限制范围内,则必须进行少量重新分配(请参阅下面的可能的优化).
如果你不有vsnprintf型的功能,我们以前用过的一招是打开的文件句柄/dev/null,并使用了相同的目的(输出到缓冲区之前检查大小).使用vfprintf该文件句柄获取大小(输出转到位桶),然后根据返回值分配足够的空间,并分配vsprintf给该缓冲区.同样,它应该足够大,因为你已经找到了所需的尺寸.
对上述方法的优化是对1K块使用本地缓冲区而不是分配的缓冲区.这避免了malloc在不必要的情况下使用,假设您的堆栈可以处理它.
换句话说,使用类似的东西:
int test(const char* format, ...)
{
char buff1k[1024];
char *buffer = buff1k; // default to local buffer, no malloc.
:
int need = 1 + vsnprintf (buffer, sizeof (buff1k), format, arguments);
if (need > sizeof (buff1k)) {
buffer = malloc (need);
// Now you have a big-enough buffer, vsprintf into there.
}
// Use string at buffer for whatever you want.
...
// Only free buffer if it was allocated.
if (buffer != buff1k)
free (buffer);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1275 次 |
| 最近记录: |