Hallo,
auf einem Microcontroller (hier ARM Cortex M3 mit GCC und newlib)
funktioniert printf ja nicht out-of-the-box, wenn der
Controllerhersteller nicht schon passende Funktionen für _write, etc.
zur Verfügung stellt. Ruft man dann printf auf, dann fliegen einem
Fehlermeldungen bzgl fehlender Funktionen wie eben _write, _sbrk, etc um
die Ohren.
Diese Funktionen muss man dann selber passend für den µC implementieren.
Hierzu hätte ich folgende Fragen:
1) mit sprintf landet die Ausgabe in einem Buffer, welchen man dann
passend an die jeweilige Schnittstelle übergeben kann. Wenn ich nun
davon ausgehe, dass die Software nicht auf einen PC portiert wird,
dann gibt es eigentlich keinen Grund, die oben genannten Funktionen zu
implementieren, oder? Falls die Software doch auf einem PC (oder
generell auf einem völlig anderen System) laufen soll, dann sollte man
es aber tun, damit man überall printf verwenden kann, korrekt?
2) Wie schwer ist die Implementierung, wenn man auf dem µC evtl mehrere
Schnittstellen wie z.B. mehrere UARTs und ein Display hat, die man per
printf ansprechen möchte? Neben den Zugriffsfunktionen (_write, etc.)
müsste man dann ja noch die Schnittstellen selbst definieren, wie
funktioniert das dann?
Ralf
Benutze doch besser fprintf. Dort kannst du einen File-Control-Block
angeben, der zur Ausgabe benutzt werden soll. Dann können beliebig viele
UARTs angesprochen werden oder LCDs, deren Ausgabefunktionen du
allerdings natürlich schreiben bzw. beistellen mußt. Im
File-Control-Block stehen u.a. die Adressen der Ein/Ausgabefunktionen,
die du dort reinschreiben mußt, ggf. durch Funktionen wie fopen. Siehe
Doku.
Ne Art von '_write' mußt Du sowieso implementieren, irgendwie muß Du
Deinen Buffer ja auch auf die Schnittstelle schreiben.
Und sprintf geht auch auf dem PC problemlos. Der Portierungsaufwand zum
PC ist nahezu derselbe, egal ob printf oder sprintf. sprintf könnte da
sogar von Vorteil sein, eventuell will man ja auch am PC die Daten auf
eine serielle Schnitstelle schreiben. Am flexibelsten dürfte die
Variante von Günter sein.
printf ist ja offensichtlich untrennbar an die Funktionen _write, _sbrk
etc. gekoppelt. Das bekommst Du nicht entkoppelt, und zur Laufzeit auf
unterschiedliche Ausgabegeräte auch nicht umgelenkt.
Mit fprintf ginge das eher, da es unterschiedliche Ausgabegeräte
bedienen kann. Hat Günter schon beschrieben.
Wenn Du dasselbe Modul auf unterschiedliche Geräte schreiben lassen
möchtest, brauchst Du dafür ein Interface. Das Interface definiert die
Funktionen. Das benutzt Du in diesem Modul und reichst von außen die
gerätespezifische Implementierung dieses Interfaces hinein oder erfragst
es per Callback.
In C wäre das ein File Pointer, in C++ würde man sich für jedes Gerät
einen eigenen Output Stream implementieren, in Java einen Writer. Zum
printf-like Formatieren in C++ braucht es Zusatzklassen (sprintf könnte
genügen), in Java gäbe es dazu den PrintWriter, der u.a. einen Writer
formatiert beschreiben kann.
Der Nachteil an sprintf ist, dass Du die Größe des Puffers vorher
festlegen musst. Mit printf bzw. fprintf kannst Du dagegen beliebig
lange und kurze Daten effizient ausgeben, indem Du jedes Zeichen live
rausschreibst.
Von daher lohnt es sich imo schon, die benötigten Funktionen zu
implementieren. Für die Variante mit sprintf brauchst Du ja am Ende auch
eine Funktion, die den fertigen String ausgibt, typischerweise bestehend
aus einer Schleife über alle Zeichen und der Ausgabe des Zeichens.
Diesen Code in ein _write zu verpacken, dürfte kein großer Aufwand zu
sein.
Hans schrieb:> Der Nachteil an sprintf ist, dass Du die Größe des Puffers vorher> festlegen musst.
Und dass man überhaupt einen Puffer braucht, der so groß ist, daß die
Ausgabe des sprintf-Aufrufs vollständig reinpasst. Dementsprechend viel
Speicher verschwendet man damit ggf.
Die Anzahl auszugebender Bytes kann mit snprintf bestimmt werden, danach
kann temporärer Speicher dafür zur Verfügung gestellt werden, z.B. per
alloca auf dem Stack oder per malloc auf dem Heap.
Schön ist das aber nicht; wenn man nicht aus anderen Gründen die Ausgabe
als String benötigt, sollte man auf diesen Zwischenschritt verzichten.
Fehlendes _sbrk deutet eher auf ein Fehlendes OS hin, printf durch
sprintf ersetzen ändert nix daran. Stellt die libgloss kein _sbrk zur
Verfügung? Oder verwendest du libnosys?
Eine eigene Frage?
Dieser Thread ist über 10 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.