Printf on Arduino

#include <stdio.h>

void setup() {
  // put your setup code here, to run once:
Serial.begin(115200);
//static FILE mystdout = FDEV_SETUP_STREAM(Serial.write(), NULL, _FDEV_SETUP_WRITE);
//stdout = &mystdout;
int i = 10;
printf("Hi %d", i);
}

void loop() {
  // put your main code here, to run repeatedly:
}

Hi , how to use printf on arduino ?
I tried example from stdio.h but no luck

printf prints to stdout.

Arduino has no stdout.

you wrong it has

it's convoluted but on AVR you can do something like this

FILE f_out;

int sput(char c, __attribute__((unused)) FILE* f) {return !Serial.write(c);}

void setup() {
  Serial.begin(115200);
  fdev_setup_stream(&f_out, sput, nullptr, _FDEV_SETUP_WRITE); // cf https://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaf41f158c022cbb6203ccd87d27301226
  stdout = &f_out;
  printf("Hello world, the answer is %d (or 0x%02X)!\n", 42, 42);
}

void loop() {}

Too slow! Here's mine:

# include <stdio.h>

int serial_putc(char c, FILE *) 
{
  Serial.write(c);

  return c;
} 

void printf_begin(void)
{
  fdevopen(&serial_putc, 0);
}

void setup() {
  Serial.begin(115200);

  printf_begin();
    
  Serial.println("Serial print, I don't like it.\n");
  
  int anInt = 32456;

  char *myChars = "good old printf! ";
  
  printf("%s %d    'K?\n\n", myChars, anInt);

  Serial.println("\nOK!");
}

void loop() {
  // put your main code here, to run repeatedly:

}

Doesn't do floating point… EDIT: @david_2018 "for those there is the dtostrf() function."

a7

printf is not functionally implemented in the standard Arduino environment, see https://playground.arduino.cc/Main/Printf/

You can use sprintf() or snprintf() to put the text into a char array, then print the array. Note that this does not supports float / double type variables, for those there is the dtostrf() function.

Some of the non-Arduino cores do support printf by default, such as MCUdude's MiniCore.

cool!

couple comments:
I guess nullptr would be better than 0 from a type point of view
also you should not return c in serial_putcif you want to send the null char out then it would be interpreted as not working. (spec states it shall return 0 if the output was successful, and a nonzero value if the character could not be sent to the device.)

void setup() {
    Serial.begin(115200);

    int i = 10;

    char s [80];
    sprintf (s, "Hi %d", i);
    Serial.println (s);
}

void loop() {
}

@J-M-L It’s just what I found when I went looking some time ago, I will apply your advices. I’m a little old fashioned when it comes to strict matters of type, that is not strict. :expressionless:

So seriaal_outc should just return 0?

Curious: in this circumstance, who is looking at the return value? I have experienced no problems with this way of printfing… except the lack of direct floating point format for the very rare occasion I even use it. Floating point.

THX

a7

yeah, bad old C habits, I've the same when I'm not careful :slight_smile:

yes, if you assume write() never fails.
I assume the AVR lib could check it, I've never looked into really. (if you return 1 it does print anyway)

No, it doesn't - you have to provide a dummy one.
(sp. "you're" or "you are" wrong)

technically avr-libc has a

#define 	stdout   (__iob[1])

and thus this will compile and run (and print 2)

void setup() {
  Serial.begin(115200);
  Serial.println(sizeof stdout);
}
void loop() {}

so it's fair to claim there is such a thing (but it does not work unless you configure it)

1 Like

A bookmark is useless without a book

fair too :wink:
(although I'm sure we can find "creative" (?) use for the bookmark even without a book)

Hi, I have not read your comments yet (I will read it now) but I am sure that J-M-L has provided solution :wink:

Now , I want to share my finding (I find two solutions.)
solution 1:
I found that FDEV_SETUP_STREAM macro is not working on Arduino (but is working on pure C) AVR C Runtime Library - Bugs: bug #36970, FDEV_SETUP_STREAM doesn't work in... [Savannah]
so we can manually define it or use fdev_setup_stream() instead.
many days I have spent to figure out that order of each line is important
so the final code is

#include <stdio.h>
int uart_putchar(char c, FILE *stream) { return Serial.write(c); }
PROGMEM const char str1[] = "Format str from flash\nlong = %15ld\nFlash string = %10S\n";

void setup() {
Serial.begin(115200);
FILE uart_str;
//FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
fdev_setup_stream(&uart_str, uart_putchar, NULL, _FDEV_SETUP_WRITE);
stdout = &uart_str;

printf("Format str from ram\nlong = %15ld\nRam string = %10s\n", 1234567890l , "string from RAM");
printf_P(str1, 1234567890l , PSTR("string form flash"));
}

void loop() {

}

I can't understand only why fdev_setup_stream() should be in setup section otherwise error :confused:
@J-M-L may be you know?

solution 2:

#include <stdio.h>
static int serial_putc(const char c, FILE *stream) { return Serial.write(c); }
static FILE *serial_stream = fdevopen(serial_putc, NULL);

void setup() {
stdout = serial_stream;
Serial.begin(115200);
printf("Format str from ram\nlong = %15ld\nRam string = %10s\n", 1234567890l , "string from RAM");
}

void loop() {

}

yeah :slight_smile: I was right , my finding the same as your code :slight_smile:
only - why you return 0 ?
got you : spec states it shall return 0 if the output was successful, and a nonzero value if the character could not be sent to the device.

hm... why it working w/o stdout = serial_stream;
:slight_smile: ) ?

Find some lib - FDEV_SETUP_STREAM - not working as docs say or my error? - #11 by krupski
maybe it will be useful to someone

I can’t explain why my code works, let alone explain why some else’s shouldn’t.

Or whatever you are asking, you talking to me?

Did you find my solution in #5 above to not work?

Are you trying to regain an ability to use printf or do you have some larger agenda?

I cannot help you.

a7

do you know/can you explain why this is code is working w/o initializing stdout ?