带Sprintf的C变量参数?

带Sprintf的C变量参数?,c,variadic-functions,C,Variadic Functions,我有一个功能 void foo(const char* format, ...) { char buffer[1080]; // Supposed way to handle C Variable Arguments? va_list argptr; va_start(argptr, format); sprintf(buffer, format, argptr); va_end(argptr); printf_s("%s.\n", b

我有一个功能

void foo(const char* format, ...)
{
    char buffer[1080];

    // Supposed way to handle C Variable Arguments?
    va_list argptr;
    va_start(argptr, format);
    sprintf(buffer, format, argptr);
    va_end(argptr);

    printf_s("%s.\n", buffer);
}

int main()
{
    int val = 53;
    foo("%d", val);
}
每次我运行这个,我都会得到大量的数字,每次运行都会发生变化<代码>12253360,
5306452
,等等。我不明白为什么

是因为我的
sprintf
调用,还是因为我在执行
va_list argptr?我的
缓冲区是否太大


谢谢。

您显然试图使用的技术表明您需要
vsprintf
(或者更好的是,
vsnprintf

这就是标准库中存在来自
v..
组的函数的原因

调用
sprintf
的方式毫无意义-它不能与外部提供的
va_列表一起使用


如果您想要实现一个可变大小的缓冲区,您可以按如下方式执行

void foo(const char* format, ...)
{
    static char *buffer;
    static size_t buffer_size;

    va_list argptr;
    va_start(argptr, format);
    int length = vsnprintf(buffer, buffer_size, format, argptr);
    va_end(argptr);

    if (length + 1 > buffer_size)
    {
      buffer_size = length + 1;
      buffer = realloc(buffer, buffer_size);
      /* Yes, `realloc` should be done differently to properly handle
         possible failures. But that's beside the point in this context */

      va_start(argptr, format);
      vsnprintf(buffer, buffer_size, format, argptr);
      va_end(argptr);
    }

    printf("%s.\n", buffer);
}

当然,您可以将内存管理策略更改为不同的策略,例如在第一次调用中使用
512
字节的固定本地缓冲区,然后仅当
512
证明不足时,才在第二次调用中使用临时动态分配的缓冲区。等等…

printf_s()
?为什么?
sprintf
不接受
va_list
类型的参数@Andrew Henle如果我使用
printf
声称它不安全,我应该使用
printf_s
。@hatefind如果我使用
printf
,我的编译器会给我一个警告。。。这是导致非标准、不可移植代码的垃圾。请参阅,它似乎是为了让没有经验的开发人员编写不可移植代码而设计的。…@hatefind明确地说,编译器警告您的函数“已弃用”和“不安全”是C语言所必需的:
printf()
不再是“弃用”的在标准C中,使用
=
赋值运算符比使用
vsnprintf()
可能是一个更好的选择,因为问题代码中有固定大小的缓冲区。@安德烈,你是说有一种方法可以使缓冲区大小不固定,因为我更喜欢这种解决方案。@hatefind:使用标准工具,您可以首先执行
int size=vsnprintf(NULL,0,…
,即使用
NULL
buffer)。这样的调用将执行“干运行”,并计算所需的确切缓冲区大小(不要忘记NULL终止符)。之后,您可以分配适当大小的缓冲区内存并再次调用
vsnprintf
,这次将新分配的缓冲区传递到那里。正如您所看到的,这需要两次传递处理。您可以自己决定,在您的情况下是否值得。@hatefind通常,我更喜欢第一次运行
vsnprintf()
使用本地非静态缓冲区,然后仅当本地缓冲区太小时才动态分配缓冲区。我对本答案中的示例所关心的一个问题是使用
静态字符*缓冲区;
使用
静态
变量使代码效率更高,但以多线程安全为代价。如果e线程同时调用
foo()
按照目前编写的,会出现严重问题。最佳解决方案取决于您如何使用该函数-您可能根本不关心线程安全。@AnT为什么要在
长度中添加一个,并检查它是否大于
缓冲区长度
长度和
缓冲区长度
的大小不应该相同吗ce
vsnprintf
返回字符串中的字符数?
void foo(const char* format, ...)
{
    static char *buffer;
    static size_t buffer_size;

    va_list argptr;
    va_start(argptr, format);
    int length = vsnprintf(buffer, buffer_size, format, argptr);
    va_end(argptr);

    if (length + 1 > buffer_size)
    {
      buffer_size = length + 1;
      buffer = realloc(buffer, buffer_size);
      /* Yes, `realloc` should be done differently to properly handle
         possible failures. But that's beside the point in this context */

      va_start(argptr, format);
      vsnprintf(buffer, buffer_size, format, argptr);
      va_end(argptr);
    }

    printf("%s.\n", buffer);
}