printf 包装器

pt1*_*lol 4 c arduino

我在 Arduino 下编码,我想开发串行打印格式化功能,所以我试图使用sprintf未知大小的缓冲区。基本上,我们可以避免谈论 Arduino 及其串行输出,而是考虑将文本写入缓冲区,然后使用printf. 我试过这个:

#include <stdio.h>
#include <stdarg.h>

void printf0( const char* format, ... ) {
    va_list args;
    va_start(args, format);
    vprintf(format, args);
    va_end( args );
}

void printf1(const char* format,...) {
  va_list args;
  va_start(args, format);
  char buf[vsnprintf(NULL, 0, format, args)];
  sprintf(buf, format, args);
  printf(buf);
  va_end(args);
}

int main()
{
    printf0("Hello, %d!\n", 15);
    printf1("Hello, %d!\n", 15);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

printf0函数是我在这里找到的一个准确示例。我的尝试是 function printf1,它产生不可预测的数字。上述程序的示例输出是:

Hello, 15!
Hello, 860799736!
Run Code Online (Sandbox Code Playgroud)

mch*_*mch 5

args是 a va_list,所以你不能sprintf用它调用。您必须使用vsprintfvsnprintf

sprintf(buf, format, args);
Run Code Online (Sandbox Code Playgroud)

应该

vsnprintf(buf, sizeof buf, format, args);
Run Code Online (Sandbox Code Playgroud)

此外,您应该buf在字符串的 0 终止符的大小上加 1 :

char buf[vsnprintf(NULL, 0, format, args) + 1];
Run Code Online (Sandbox Code Playgroud)

似乎第一次调用vsnprintf改变了args,所以你必须添加

va_end(args);
va_start(args, format);
Run Code Online (Sandbox Code Playgroud)

两次通话之间:http : //ideone.com/5YI4Or

似乎第一次调用vsnprintf改变了args,但你不应该调用va_start两次。你应该va_copy改用,所以添加

va_list args2;
va_copy(args2, args);
Run Code Online (Sandbox Code Playgroud)

初始化后args。也不要忘记打电话va_end(args2);

http://ideone.com/loTRNL

链接到va_copy手册页:https : //linux.die.net/man/3/va_copy

  • 与其做两次`va_start`,你应该用它来代替`va_copy`。标准明确指出*“在访问未命名参数之前,应调用 va_start 宏。”* (2认同)