Hallo,
um printf()/scanf() auf einem Mikrocontrollersystem ans laufen zu
bekommen, muss man unter GCC ja mindestens die Systemaufrufe für
_read()/_write() implementieren und für STDIN/STDOUT/STDERR auf einen
UART anpassen.
Wenn man im Web nach Beispielen für die Implementierung sucht, dann
findet man hauptsächlich (eigentlich nur) Implementierungen, welche
_read() blockierend ausführen, d.h. es muss mindestens ein Zeichen
empfangen worden sein.
Das scheint ja für die meisten Anwender so zu funktionieren, aber wenn
ich nun bspw. anstatt scanf() Funktionen für einzelne Zeichen
(getchar(), getc(), etc) verwenden möchte und mir die Beschreibungen der
Funktionen anschaue, dann können die auch EOF (= kein Zeichen empfangen
= Rückgabewert 0) zurückliefern.
Frage: wenn man's ganz richtig machen will, dann darf _read() demnach
nicht blockierend ausgeführt sein und muss EOF bzw. 0 zurückliefern,
wenn zum Aufrufzeitpunkt nichts empfangen ist, korrekt?
Danke
Ralf
Ralf schrieb:> dann können die auch EOF (= kein Zeichen empfangen = Rückgabewert 0)> zurückliefern.
Aber nur im Fehlerfall oder eben bei End Of File. Wenn einfach nur keine
Zeichen da sind, soll _read() blockieren. Wie sonst soll scanf() darauf
warten, dass alles angekommen ist?
Niklas G. schrieb:> Ralf schrieb:>> dann können die auch EOF (= kein Zeichen empfangen = Rückgabewert 0)>> zurückliefern.
Korrektur: Ich hab hier einen Fehler, EOF ist nicht 0, sondern -1.
> Aber nur im Fehlerfall oder eben bei End Of File. Wenn einfach nur keine> Zeichen da sind, soll _read() blockieren. Wie sonst soll scanf() darauf> warten, dass alles angekommen ist?
Meine Vermutung(!) wäre, dass scanf() _read() solange aufruft bis != EOF
zurückgegeben wird.
Ralf
Ralf schrieb:> Meine Vermutung(!) wäre, dass scanf() _read() solange aufruft bis != EOF> zurückgegeben wird.
Nene, das wäre ja super ineffizient. Bei EOF kehrt scanf() sofort
zurück. Schau doch in den Sourcecode von scanf()...
Niklas G. schrieb:> Ralf schrieb:>> Meine Vermutung(!) wäre, dass scanf() _read() solange aufruft bis != EOF>> zurückgegeben wird.> Nene, das wäre ja super ineffizient. Bei EOF kehrt scanf() sofort> zurück. Schau doch in den Sourcecode von scanf()...
Dann versteh ich nicht, unter welchen Umständen getchar() überhaupt EOF
zurückgibt, wenn STDIN als Eingabe verwendet wird? Bei getc() ist es
klar, das bekommt einen FileDescriptor mitgeteilt, da kann (wird) EOF
dann vorkommen.
Für den Sourcecode meinst du sourceware.org? Ich schau mal ob ich mich
da zurechtfinde :)
Vielleicht sollte ich besser schildern, was ich vorhabe: ich möchte
einzelne Zeichen vom UART lesen - alle Zeichen bis auf ein spezielles
sollen ganz normal weiter an eine andere Funktion durchgereicht werden.
Wenn das spezielle Zeichen empfangen wird, dann soll über eine bestimmte
Zeit geprüft werden, ob weitere Zeichen empfangen wurden oder nicht.
Wenn ja, alles inklusive des speziellen Zeichens weiter durchreichen,
ansonsten eben was spezielles machen.
Also im Prinzip beim Empfang des speziellen Zeichens einen Timeout auf
den Empfang weiterer Zeichen einrichten.
Mit einem nicht blockierenden _read() unter der Haube, welches EOF für
"keine Daten vorhanden" ausspuckt hätte ich nun gedacht, dass das gehen
könnte, bspw. mit getchar().
Also mal der aktuelle Fragenkatalog:
1) _read() muss blockierend sein und kann kein EOF liefern?
2) Unter welchen Umständen spuckt getchar() dann ein EOF aus, wenn
dieses nicht von _write() kommen kann?
3) Wie richtet man eine nicht blockierende Abfrage von STDIN ein?
getc()/getchar() in Kombination mit ungetc() auf STDIN?
Ralf
Hab da grad nochmal genauer drüber nachgedacht:
> 1) _read() muss blockierend sein und kann kein EOF liefern?
Anstatt EOF für keine Daten würde ja 0 auch gehen, wenn nichts im Buffer
ist - read() gibt ja die Menge der gelesenen Daten zurück. Kommt scanf()
dann eher damit klar? Das würde es scanf() auch ermöglichen zu prüfen ob
was angekommen ist. Damit wäre es aber trotzdem nicht blockierend.
Ralf
Ralf schrieb:> Dann versteh ich nicht, unter welchen Umständen getchar() überhaupt EOF> zurückgibt, wenn STDIN als Eingabe verwendet wird?
Wenn stdin geschlossen wurde oder "am Ende angekommen" ist, oder bei
einem Fehler. stdin muss ja nicht von z.B. einer RS232 kommen, sondern
kann auch aus einer Datei lesen. Bei Kommandozeilentools auf dem Rechner
ist das nicht so ungewöhnlich. Und wenn das Ende dieser Datei erreicht
ist, kommt halt ein EOF.
> Bei getc() ist es klar, das bekommt einen FileDescriptor mitgeteilt, da> kann (wird) EOF dann vorkommen.
getchar ist nix anderes als getc(stdin).
> 3) Wie richtet man eine nicht blockierende Abfrage von STDIN ein?> getc()/getchar() in Kombination mit ungetc() auf STDIN?
Nein. In Standard-C gibt's keinen Weg dafür.
Ralf schrieb:>> 1) _read() muss blockierend sein und kann kein EOF liefern?> Anstatt EOF für keine Daten würde ja 0 auch gehen, wenn nichts im Buffer> ist - read() gibt ja die Menge der gelesenen Daten zurück.
Ja, und wenn es keine Daten mehr lesen kann, liefert es das zurück, was
dann bedeutet, dass das EOF erreicht ist. Wenn gerade keine Daten
verfügbar sind, liefert es nichts zurück, weil es blockiert.
Rolf M. schrieb:>> 3) Wie richtet man eine nicht blockierende Abfrage von STDIN ein?>> getc()/getchar() in Kombination mit ungetc() auf STDIN?> Nein. In Standard-C gibt's keinen Weg dafür.
Das ist wohl korrekt, wie ich mittlerweile feststellen musste.
> Ralf schrieb:>>> 1) _read() muss blockierend sein und kann kein EOF liefern?>> Anstatt EOF für keine Daten würde ja 0 auch gehen, wenn nichts im Buffer>> ist - read() gibt ja die Menge der gelesenen Daten zurück.> Ja, und wenn es keine Daten mehr lesen kann, liefert es das zurück, was> dann bedeutet, dass das EOF erreicht ist. Wenn gerade keine Daten> verfügbar sind, liefert es nichts zurück, weil es blockiert.
Habe den von Niklas implizierten Versuch durchgeführt, also scanf() mit
einem nicht blockierenden _read() - scanf() ist wie von Niklas erwartet
sang- und klanglos durchgerauscht :)
Ich muss mir mal überlegen wie ich das lösen kann. Notfalls muss ich
eben doch den UART-Puffer vorher prüfen ob was drin ist, das wollte ich
eigentlich vermeiden.
Danke euch beiden.
Ralf
Ralf schrieb:> Wenn man im Web nach Beispielen für die Implementierung sucht, dann> findet man hauptsächlich (eigentlich nur) Implementierungen, welche> _read() blockierend ausführen, d.h. es muss mindestens ein Zeichen> empfangen worden sein.
Das ist korrekt, read() blockiert standardmäßig. Es ist aber kein
Problem, noch eine ioctl()-Funktion hinzuzufügen, mit welcher man ein
Flag setzen kann, dass read() ab sofort nicht mehr blockieren soll.
Unix/Linux machen es so. Dieses Vorgehen kann problemlos auf einem µC
analog dazu implementiert werden.
Frank M. schrieb:> Das ist korrekt, read() blockiert standardmäßig. Es ist aber kein> Problem, noch eine ioctl()-Funktion hinzuzufügen, mit welcher man ein> Flag setzen kann, dass read() ab sofort nicht mehr blockieren soll.> Unix/Linux machen es so. Dieses Vorgehen kann problemlos auf einem µC> analog dazu implementiert werden.
Standardfunktionen wie scanf() werden aber trotzdem nicht funktionieren,
wenn man denen hinterrücks den stream non-blocking macht.