Serial printf implementation 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?
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.