Forum: Compiler & IDEs GCC, newlib/libgloss: Frage zur Anpassung der _read() Funktion


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Ralf (Gast)


Lesenswert?

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

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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?

von Ralf (Gast)


Lesenswert?

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

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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()...

von Ralf (Gast)


Lesenswert?

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

von Ralf (Gast)


Lesenswert?

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

von Rolf M. (rmagnus)


Lesenswert?

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.

: Bearbeitet durch User
von Ralf (Gast)


Lesenswert?

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

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.