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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8488671/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 18:38:37  来源:igfitidea点击:

Unix to Windows: Alternative to vsnprintf to determine length?

cwindowsvisual-studio-2010

提问by lx.

I am currently converting the code of one of our Linux libraries to a Windows DLL.

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

Within this library I have a function which takes the last parameters in a printf-way (format string, then ellipsis). Within this function I use vsnprintf to format the supplied arguments. Since I want to know whether I can cram the final string into a small buffer or if I'd have to allocate memory for it, I am interested in determining the "would-be-length" of the formatted string.

在这个库中,我有一个函数,它以 printf 方式(格式字符串,然后是省略号)获取最后一个参数。在这个函数中,我使用 vsnprintf 来格式化提供的参数。由于我想知道是否可以将最终字符串填充到一个小缓冲区中,或者是否必须为其分配内存,因此我对确定格式化字符串的“长度”感兴趣。

To do this, I am currently using vsnprintf like this (made up example code, obviously):

为此,我目前正在使用这样的 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);
}

This usage is covered by the Open Group Base Specifications Issue 6:

Open Group Base Specifications Issue 6涵盖了这种用法:

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

The [...] vsnprintf() [...] functions shall be equivalent to [...] snprintf().

snprintf(char *restrict s, size_t n, const char *restrict format, ...)

If the value of n is zero on a call to snprintf(), nothing shall be written, the number of bytes that would have been written had n been sufficiently large excluding the terminating null shall be returned, and s may be a null pointer.

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 的值为零,则不应写入任何内容,如果 n 足够大,则应返回不包括终止空值的字节数,并且 s 可能是空指针。

The problem arised as I was compiling this code on the Windows-System (Visual Studio 2010) with /analyze on. The compiler/analyzer gave me the following:

当我在 Windows 系统(Visual Studio 2010)上使用 /analyze 编译此代码时出现了问题。编译器/分析器给了我以下信息:

test.c(11) : warning C6309: Argument '1' is null: this does not adhere to function specification of 'vsnprintf'

test.c(11) : warning C6387: 'argument 1' might be '0': this does not adhere to the specification for the function 'vsnprintf': Lines: 7, 8, 10, 11

test.c(11):警告 C6309:参数“1”为空:这不符合“vsnprintf”的功能规范

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

A quick look at the MSDN entry for vsnprintfgave me this:

快速查看vsnprintfMSDN 条目给了我这个:

If bufferor formatis NULL, or if count is less than or equal to zero, these functions invoke the invalid parameter handler, as described in Parameter Validation. If execution is allowed to continue, these functions return -1.

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

Curious enough, the above sample works nonetheless on Windows "as expected" (i.e. it returns to me the count of the characters that would be written).

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

But since I don't want this to rely on something unspecified I'd like to know if there is a better, official way of achieving the same, without having to hope that this won't break in some future release.

但是由于我不希望这依赖于未指定的东西,我想知道是否有更好的官方方法来实现相同的目标,而不必希望这不会在将来的某个版本中中断。

Thanks for your time!

谢谢你的时间!

采纳答案by lx.

Answer provided in comments by Hans Passant:

Hans Passant在评论中提供的答案:

The documented _vscprintfprovides this functionality on Windows, so relying on "unspecified behaviour" is not necessary.

记录在案的 _vscprintf在 Windows 上提供了此功能,因此没有必要依赖“未指定的行为”。

回答by INS

Take this example from the manual page of snprintf:

snprintf手册页中获取此示例:

Here is how to allocate a buffer in order to fit your string.

以下是如何分配缓冲区以适合您的字符串。

#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;
        }
    }
}