Based on this approach I wanted to implement a function for formatted printing data to the serial monitor. I tried the code below:
int PIN = 12;
void _printf(char *fmt, ...) {
va_list va;
va_start(va, fmt);
char buf[vsnprintf(NULL, 0, fmt, va) + 1];
sprintf(buf, fmt, va);
Serial.println(buf);
va_end(va);
}
void setup() {
Serial.begin(9600);
Serial.println("serial monitor has been set up");
char buf0[vsnprintf(NULL, 0, "pin %i configured to output", PIN) + 1];
sprintf(buf0, "pin %i configured to output", PIN);
Serial.println(buf0);
_printf("pin %i configured to output", PIN);
char buf1[vsnprintf(NULL, 0, "pin %i configured to output", PIN) + 1];
sprintf(buf1, "pin %i configured to output", PIN);
Serial.println(buf1);
_printf("pin %i configured to output", PIN);
pinMode(PIN, OUTPUT);
char buf2[vsnprintf(NULL, 0, "pin %i configured to output", PIN) + 1];
sprintf(buf2, "pin %i configured to output", PIN);
Serial.println(buf2);
_printf("pin %i configured to output", PIN);
char buf3[vsnprintf(NULL, 0, "pin %i configured to output", PIN) + 1];
sprintf(buf3, "pin %i configured to output", PIN);
Serial.println(buf3);
_printf("pin %i configured to output", PIN);
}
void loop() { }
But it gives me some weird output:
serial monitor has been set up
pin 12 configured to output
pin 2263 configured to output
pin 12 configured to output
pin 2234 configured to output
pin 12 configured to output
pin 2205 configured to output
pin 12 configured to output
pin 2176 configured to output
What do 2263
and 2269
mean? Why does it happen only inside the function? What is my mistake and how can I fix it?
1 Answer 1
The problem with your code is that you are mixing the "normal" and "variadic" forms of the printf functions.
Any printf function starting with V takes a variadic argument list pointer as its last variable. Any printf function which doesn't start with V takes a variadic list of individual variables.
When calculating your buffer size from a list of variables in your main loop you are incorrectly using vsnprintf
- you should be using snprintf
since you aren't passing it a va_list
, but individual variables. In your _printf
function you are correctly using vsnprintf
to calculate the length of the buffer, but then incorrectly using sprintf
with a va_list
instead of individual variables.
So your two forms should actually be re-written as:
// Inline version
char buf0[snprintf(NULL, 0, "pin %i configured to output", PIN) + 1];
sprintf(buf0, "pin %i configured to output", PIN);
Serial.println(buf0);
and:
void _printf(char *fmt, ...) {
va_list va;
va_start(va, fmt);
char buf[vsnprintf(NULL, 0, fmt, va) + 1];
vsprintf(buf, fmt, va);
Serial.println(buf);
va_end(va);
}
Remember: if you have a va_list
then it goes with a v*printf
function. If you have individual variables they go with a *printf
function.
printf()
?Streaming.h
lets you write code that's rather more clear, using a lot less memory and producing much less assembly code. See for example my answer to question 33319 that explains how to use it