目标:将数据序列化为JSON。
问题:我事先不知道整数是多少个字符。
我认为一个好方法是使用sprintf()
size_t length = sprintf(no_buff, "{data:%d}",12312);
char *buff = malloc(length);
snprintf(buff, length, "{data:%d}",12312);
//buff is passed on ...
当然我可以使用像char a[256]
这样的堆栈变量而不是no_buff
。
问题:但是在C中是否存在像unix /dev/null
这样的一次性写入的实用程序?
像这样的Smth:
#define FORGET_ABOUT_THIS ...
size_t length = sprintf(FORGET_ABOUT_THIS, "{data:%d}",12312);
P.S。我知道我也可以通过日志获得整数的长度,但这种方式看起来更好。
答案 0 :(得分:17)
由于C是简单语言的地方,没有“一次性缓冲区”这样的东西 - 所有内存管理都在程序员的肩膀上(这些有GNU C编译器扩展,但它们不是标准的)。
事先不知道整数是多少个字符。
您的问题有更简单的解决方案。 snprintf
知道!
在兼容C99的平台上,使用NULL作为第一个参数调用snprintf:
ssize_t bufsz = snprintf(NULL, 0, "{data:%d}",12312);
char* buf = malloc(bufsz + 1);
snprintf(buf, bufsz + 1, "{data:%d}",12312);
...
free(buf);
在较旧的Visual Studio版本(具有非C99兼容的CRT)中,使用_scprintf
代替snprintf(NULL, ...)
调用。
答案 1 :(得分:12)
您可以致电int len = snprintf(NULL, 0, "{data:%d}", 12312)
来测试您需要多少空间。
snprintf
将打印最多size
个字符,其中size
是第二个参数,并返回打印整个内容所需的字符数,不计算终止{ {1}}。因为你传入0,它实际上不会写任何东西(因此将避免通过尝试取消引用'\0'
)而发生的任何空指针异常,但它仍将返回所需的长度适合整个输出,您可以使用它来分配缓冲区。
此时,您可以分配并打印到缓冲区,还记得为尾随NULL
添加一个:
'\0'
答案 2 :(得分:5)
要获得你可以写的长度:
int length = snprintf(NULL, 0, "{data:%d}", 12312);
请注意,返回类型为int
。如果出现某种错误,它可能会返回-1
。确保您的输入数据不包含可能导致总长度超过INT_MAX
的长字符串!
答案 3 :(得分:0)
如果检查性能,那么在没有输出缓冲区的情况下运行snprintf将花费与完全调用大致相同的时间。
因此,我建议您使用较小的缓冲区以防万一,如果返回的大小超过缓冲区大小,则只调用它一次。
这使用C ++的std::string
,但我想你可以根据自己的需要调整它。
std::string format(const char* format, ...) {
va_list args;
va_start(args, format);
char smallBuffer[1024];
int size = vsnprintf(smallBuffer, sizeof smallBuffer, format, args);
va_end(args);
if (size < sizeof smallBuffer)
return std::string(smallBuffer);
char buffer[size + 1]; /* maybe malloc if it's too big */
va_start(args, format);
vsnprintf(buffer, sizeof buffer, format, args);
va_end(args);
return std::string(buffer);
}
对于1k以下的字符串,与较长的字符串相比,此代码的运行速度提高2倍。
答案 4 :(得分:0)
Printf支持%n格式参数,这意味着“将%n在输出字符串中的位置写入x参数所指向的int值),因此:
int x;snprintf(NULL, 0, "Message: %s%n", "Error!",&x);
应该可以!
答案 5 :(得分:0)
调用snprintf(nullptr,0,...)确实会返回大小,但是会降低性能,因为它将调用IO_str_overflow并且很慢。
如果您确实关心性能,则可以预先分配一个虚拟缓冲区,并将其指针和大小传递给:: snprintf。它将比nullptr版本快几倍。
template<typename ...Args>
size_t get_len(const char* format, Args ...args) {
static char dummy[4096]; // you can change the default size
return ::snprintf(dummy, 4096, format, args...) + 1; // +1 for \0
}
答案 6 :(得分:-1)
这不是对您的问题的严格答案,但您可能会发现它仍然有用。它不是可移植的,但是如果你在glibc上运行它,你可以简单地使用asprintf()
,这将为你做内存分配。