fprintf ohne stdio?

#7080565
Lesenswert?

Servus!

mal angenommen, man meint -ffreestanding ernst, es gibt keine libc und 
selbst "Simply the best printf around the net"¹ ist noch zu fett. Ein 
kleines printf(), z.B. aus einem alten ChibiOS, gönnt man sich trotzdem.

So ein printf() kann seine Ausgabe ungepuffert über ein extrem einfaches 
putchar() machen. Für ein UART reichen 2 Zeilen. Für ein LCD mit HD44780 
braucht es kaum mehr. Alles trivial, solange es nur UART oder LCD 
gibt.

Damit man so ein printf() für UART und LCD nutzen kann, baut man 
einfach ein putchar(), das seinerseits über einen Pointer entweder 
uart_put() oder lcd_put() aufruft. Im Unterschied zu fprintf() und 
fputc() muss man nicht überall den FILE Pointer mitgeben. Stattdessen 
braucht man eine Funktion, mit der man zwischen den Ausgabekanälen 
umschalten kann. Also ungefähr etwas wie freopen() für stdout, nur 
einfacher, weil es kein close() und open() gibt (geben soll).

Natürlich nimmt man für größere uC stdio, aber für kleinere scheint mir 
diese Lösung geradezu elegant zu sein (mal abgesehen von einem besseren 
Namen statt reopen). Andererseits finde ich praktisch nur Beiträge, die 
entweder mit "nimm stdio" oder mit sprintf() enden. Wo ist der Fehler?
1
// putchar.h
2
typedef int putchar_ptr (int);
3
int putchar (int c);
4
int uart2_put (int c);
5
int lcd_put (int c);
6

7
// putchar.c
8
static putchar_ptr  *do_putchar = uart2_put;
9

10
void
11
reopen (putchar_ptr *fun)
12
{
13
   do_putchar = fun;
14
   return;
15
}
16

17
int
18
putchar (int c)
19
{
20
   assert (do_putchar != NULL);
21
   if (c == '\n' && no_nlcr == 0) {
22
      do_putchar ('\r');
23
   }
24
   return do_putchar (c);
25
}
1) https://github.com/mpaland/printf
Gast #7080680
Lesenswert?

> also eine Lösung mit FILE *; genau das wollte ich doch vermeiden.

Hast du dir das Beispiel mal angeschaut?
1
static int
2
myputchar(char c, FILE *stream)
3
{
4
  if (c == '\n')
5
    do_putchar('\r');
6
  do_putchar(c);
7
  return 0;
8
}
9

10
static FILE uart = FDEV_SETUP_STREAM(myputchar, NULL, _FDEV_SETUP_WRITE);
11

12
int
13
main(void)
14
{
15
  ... init ...
16
  stdout = &uart;  // dein reopen
17
  printf("Hello, world!\n");
18

19
  return 0;
20
}

Im avr-libc ist das FILE-Handling extrem mager - ein FILE ist nur ein 
paar Bytes größer als dein vergleichbarer putchar_ptr.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren