Unix到Windows:替代vsnprintf来确定长度?

我目前正在将我们的一个Linux库的代码转换为Windows DLL。

在这个库中,我有一个函数,它采用printf方式的最后一个参数(格式string,然后是省略号)。 在这个函数中,我使用vsnprintf来格式化提供的参数。 由于我想知道是否可以将最终string塞进一个小缓冲区,或者如果我不得不为它分配内存,我有兴趣确定格式化string的“可能长度”。

要做到这一点,我目前正在使用vsnprintf(显然是由示例代码组成的):

#include <stdio.h> #include <stdlib.h> #include <stdarg.h> void foo(const char* fmt, ...) { int len = 0; va_list ap; va_start(ap, fmt); len = vsnprintf(0, 0, fmt, ap); printf("len = %d\n", len); va_end(ap); } int main(void) { foo("12345%s", "67890"); exit(0); } 

这个用法包含在Open Group Base Specification第6期中 :

vsnprintf(char * restrict s,size_t n,const char * restrict格式,va_list ap)

vsnprintf()函数应该相当于snprintf()。

snprintf(char * restrict s,size_t n,const char * restrict格式,…)

如果在对snprintf()的调用中n的值为零,则不应该写入任何内容,将被写入的字节数足够大,不包括结束的空值将被返回,并且s可以是空指针。

当我在Windows系统(Visual Studio 2010)上用/ analyze编译这段代码时,问题就出现了。 编译器/分析器给了我以下内容:

test.c(11):警告C6309:参数'1'为空:这不符合'vsnprintf'函数规范

test.c(11):警告C6387:'参数1'可能是'0':这不符合函数'vsnprintf'的规范:行数:7,8,10,11

快速查看vsnprintf的MSDN条目给了我这个:

如果缓冲区格式NULL ,或者count小于或等于零,则这些函数将调用无效参数处理程序,如参数validation中所述。 如果允许继续执行,这些函数返回-1。

好奇的是,上面的示例仍然在Windows上“按预期”工作(即它返回到我将被写入的字符的计数)。

但是因为我不希望这个依赖于某个未指定的东西,所以我想知道是否有一个更好的,正式的实现方式,而不必指望这个版本在未来的版本中不会被打破。

谢谢你的时间!

Solutions Collecting From Web of "Unix到Windows:替代vsnprintf来确定长度?"

Hans Passant评论中提供的答复:

有记录的_vscprintf在Windows上提供了这个功能,所以依靠“未指定的行为”是没有必要的。

从snprintf的手册页拿这个例子:

这里是如何分配一个缓冲区,以适应你的字符串。

 #include <stdio.h> #include <stdlib.h> #include <stdarg.h> char * make_message(const char *fmt, ...) { int n; int size = 100; /* Guess we need no more than 100 bytes. */ char *p, *np; va_list ap; if ((p = malloc(size)) == NULL) return NULL; while (1) { /* Try to print in the allocated space. */ va_start(ap, fmt); n = vsnprintf(p, size, fmt, ap); va_end(ap); /* If that worked, return the string. */ if (n > -1 && n < size) return p; /* Else try again with more space. */ if (n > -1) /* glibc 2.1 */ size = n+1; /* precisely what is needed */ else /* glibc 2.0 */ size *= 2; /* twice the old size */ if ((np = realloc (p, size)) == NULL) { free(p); return NULL; } else { p = np; } } }