Forum: PC-Programmierung MSVC: printf mit eigenem putchar


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,
ich nutze den Microsoft Visual Studio Compiler 2010 unter Windows 7. 
(Ich nutze ihn als MEX-Compiler für Matlab, aber das ist für die 
Fragestellung vermutlich nicht relevant - er verhält sich wie in der 
normalen Konsole.)

In meinem Programm sind *printf*-Aufrufe, die ich auf meine eigene 
putchar-Routine umleiten will (so, wie ich es beim AVR-GCC oder beim 
ARM-GCC gewohnt bin).

Nur wie schiebt man dem stdout seine eigene putchar unter?

Viele Grüße
W.T.

von Luther B. (luther-blissett)


Lesenswert?

Die MSVC StreamsIO Bibliothek sieht so was nicht vor. Du kannst so etwas 
ähnliches machen, in dem du:

- Mit _pipe() zwei pipe file desriptoren erstellst.
- Mit _fdopen() aus dem beschreibbaren handle wieder einen FILE* machst. 
Auf den kannst du jetzt mit fprintf() schreiben.
- Einen thread startest, der das lesbare Ende der pipe ausliest und 
weiterverarbeitet.

von Walter T. (nicolas)


Lesenswert?

Hallo Luther,
danke für die Antwort.

> - Mit _pipe() zwei pipe file desriptoren erstellst.
> - Mit _fdopen() aus dem beschreibbaren handle wieder einen FILE* machst.
> Auf den kannst du jetzt mit fprintf() schreiben.
> - Einen thread startest, der das lesbare Ende der pipe ausliest und
> weiterverarbeitet.

Das klingt nicht so, als ob es Spaß machen würde. Also wird es 
vermutlich auf eine eigene Implementierung für printf hinauslaufen.

Viele Grüße
W.T.

von Peter II (Gast)


Lesenswert?

Walter Tarpan schrieb:
> Das klingt nicht so, als ob es Spaß machen würde. Also wird es
> vermutlich auf eine eigene Implementierung für printf hinauslaufen.

und warum nicht einfach sprintf verwenden?

Was willst du denn genau machen?

von Yalu X. (yalu) (Moderator)


Lesenswert?

Hier ist Code für ein printf, das auf vsnprintf aufbaut und eine
selbstdefinierte putchar-Funktion aufruft:
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <stdarg.h>
4
5
// Beispiel-putchar fuer Sperrschrift
6
7
int myputchar(int c) {
8
  putchar(c);
9
  putchar(' ');
10
  return c;
11
}
12
13
int myprintf(const char * restrict format, ...) {
14
  char * buffer;
15
  va_list args;
16
  int i, ret;
17
18
  // Formatierung zur Probe, um die Laenge der Ausgabe bestimmen
19
20
  va_start(args, format);
21
  ret = vsnprintf(NULL, 0, format, args);
22
  va_end(args);
23
24
  if(ret <= 0)
25
    return ret;
26
27
  // Puffer fuer vsnprintf anlegen
28
29
  buffer = malloc(ret+1);
30
  if(buffer == NULL)
31
    return -1;
32
33
  // Endgueltige Formatierung
34
35
  va_start(args, format);
36
  ret = vsnprintf(buffer, ret+1, format, args);
37
  va_end(args);
38
39
  // Ausgabe mit selbstdefinierter putchar-Funktion
40
41
  for(i=0; i<ret; i++)
42
    myputchar(buffer[i]);
43
44
  free(buffer);
45
46
  return ret;
47
}
48
49
#define printf myprintf
50
51
52
// Beispielaufruf
53
54
int main(void) {
55
  printf("Ergebnis: %d\n", 12345);
56
  return 0;
57
}

Nachteilig ist der zweimalige Aufruf von vsnprintf, der für die
Bestimmung der erforderlichen Puffergröße benötigt wird. Du kannst
dieses Problem evtl. auf zweierlei Weise umgehen:

1. Wenn du weißt, wie lang jede Ausgabe maximal werden kann, kannst du
   mit einem statischen Puffer arbeiten und kommst damit mit einem
   einzelnen vsnprintf aus.

2. Falls deine Laufzeitbibliothek asprintf o.ä. unterstützt, kannst du
   dieses anstelle der beiden vsnprintf verwenden.

von Walter T. (nicolas)


Lesenswert?

Hallo Peter,
ich drehe mal Deine Zeilen um:
> Was willst du denn genau machen?

Ich nutze Matlab, um Funktionen, die bislang auf einem STM32 und einem 
ATmega644 laufen zu testen. Dafür habe ich mir (u. A.) eine kleine 
Display-Emulation geschrieben, die die Grafik-Display-Ausgabe in Matlab 
darstellt. Hauptzweck der Sache sind natürlich Tests einiger 
Fixpoint-Routinen gegen die Ergebnisse der Floating-Point-Routinen in 
Matlab.

Und da sowohl mit AVR-GCC als auch ARM-GCC sich die printf-Funktionen 
auf jede Schnittstelle umleiten lassen, ist der legacy code - 
insbesondere die Testfunktionen - gespickt mit Ausgaben über printf, 
hauptsächlich aus dem Grund, daß ich dann nicht überall besondere header 
einbinden muß, sondern stdio ausreicht.

Peter II schrieb:
> und warum nicht einfach sprintf verwenden?
>

Der Hauptgrund ist lediglich: Ausgabe mit sprintf braucht zwei Zeilen, 
Einbindung einer Headerdatei für die Ausgabefunktion und einen globalen 
Stringpuffer. Nichts Weltbewegendes. Nur Komfort. Und jetzt suche ich 
auf dem PC nach dem gleichen Komfort wie am µC.

Viele Grüße
W.T.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Hallo Yalu,
danke für den Vorschlag. Das dürfte sich ziemlich komfortabel umsetzen 
lassen. Mit snprintf und einem festen Puffer wird das sogar sehr 
übersichtlich.

Vielen Dank und viele Grüße
W.T.

P.S.: Zu früh gefreut. Der "restrict" ist C99, das kann der MSVC nicht. 
Aber wenn ich das Detail weglasse funktioniert es auf Anhieb.

: Bearbeitet durch User
von Yalu X. (yalu) (Moderator)


Lesenswert?

Walter Tarpan schrieb:
> P.S.: Zu früh gefreut. Der "restrict" ist C99, das kann der MSVC nicht.
> Aber wenn ich das Detail weglasse funktioniert es auf Anhieb.

Ja, lass es weg. Ich habe es hauptsächlich deswegen hingeschrieben, 
damit myprintf die gleiche Signatur wie (C99-)printf hat.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.