Karl Heinz Buchegger schrieb:
> Was genau ein Terminal beim Drücken der Return Taste sendet, ist bei
> einem Terminal normalerweise einstellbar.
Das ist korrekt, der Standardwert (Default) ist aber immer CR ('\r').
Die Taste heißt nicht umsonst RETURN, denn sie ist die frühere
Wagenrücklauftaste (Carriage Return) bei den Teletypes (TTY). Und da
konnte man das gar nicht umstellen ;-)
Um die Verwirrung perfekt zu machen, hole ich mal etwas weiter aus und
versuche aus der Historie zu erklären, wieso es heute immer noch ein
Problem ist:
UNIX wurde Anfang der 70er Jahre entwickelt. Als Zeilentrenner für
Dateien wurde das NL ('\n' "NewLine") gewählt. Die Teletypes sendeten
aber schon damals bei Drücken auf die RETURN-Taste ein CR ('\r'). Aus
diesem Grunde mappte der Treiber einer UNIX-Console (und aller anderen
vorhandenen TTYs) das CR ('\r') wieder zurück auf NL ('\n'). Diese
Einstellung hat sich bis heute in allen UNIX-Derivaten gehalten - auch
unter Linux. Nur deshalb kann man in C zum Beispiel schreiben:
1 | while ((ch = getchar()) != '\n')
|
2 | {
|
3 | // tu was
|
4 | }
|
So ein C-Programm lässt sich damit sowohl mit einem UNIX/Linux-TTY als
auch per stdin-Redirection auf Dateien anwenden (wo unter UNIX immer
'\n' als Zeilentrenner drin steht). Das ist nur dem CR->NL-Mapping des
Unix-TTY-Treibers zu verdanken.
Die stty-Einstellung dazu heisst 'icrnl' und lässt sich mit 'stty
-icrnl' in der Shell wieder abschalten. Dann "sieht" man wieder die
Original-CR-Taste und man muss '\r' in seinem C-Programm schreiben, um
die RETURN-Taste abzufragen.
Auf einem µC gibt es dieses CR->NL Mapping natürlich nicht. Deshalb ist
es erstmal die richtige Vorgehensweise, das CR ('\r') als Standard
anzunehmen.
Natürlich hast Du Recht, wenn Du schreibst, dass man hier flexibel sein
sollte, also dass man sowohl '\r' als auch '\n' in seinen µC-Programmen
als Zeilentrenner akzeptiert. Ich selbst checke immer sowohl auf '\r'
als auch auf '\n' und ignoriere dann ein nachfolgendes NL ('\n'), wenn
ich schon ein CR ('\r') empfangen habe.
Diese Kombination CR + NL ('\r' gefolgt von einem '\n') haben wir dem
VAX/VMS-Betriebssystem vom damaligen Hersteller DEC zu verdanken. Hier
wurde als Zeilentrenner die Kombination aus beiden Zeichen gewählt.
Microsoft hat das damals für MSDOS dann auch so übernommen. Dies liegt
wohl an den damaligen Druckern, die immer ein CR für den Wagenrücklauf
und dann ein NL für den Zeilenvorschub erwarten. Auch die damaligen
Teletypes (und später auch Terminals) erwarteten beides! Aus diesem
Grunde mappt der TTY-Treiber eines Unix-Systems bei der Ausgabe das NL
wieder auf CR + NL. ("onlcr" im TTY-Treiber, kann man mit "stty -onlcr"
abschalten).
Somit kann man dann in C einfach schreiben:
putchar ('\n');
Der TTY-Treiber hat daraus dann CR+NL gemacht :-)
Man sieht: Diese ganze Verwirrung war damals durch UNIX (woher die
Sprache C stammt) schon vorprogrammiert. Der Input eines Terminals wurde
von CR nach NL gemappt, der Output von NL nach CR + NL. Und das ganz nur
aus einem einzigen Grunde: Kompatibilität mit I/O-Redirection
(Umlenkung) auf Dateien, wo IMMER nur ein einzelnes NL als Zeilentrenner
gespeichert wurde.
Die Entwickler von VMS und MSDOS haben diesen Hickhack nicht mitgemacht,
sie haben sich einfach für CR + NL als Zeilentrenner in Dateien
entschieden. Das wiederum erforderte Anpassungen des C-Runtime-Systems
an diese beiden Betriebssysteme: bei der Ausgabe wird das '\n' aus C in
CR + NL gewandelt und ein CR+NL aus einer Datei in ein einfaches NL. Das
macht hier aber nicht der TTY-Treiber, sondern hier die
C-Runtime-Bibliothek.
Dies wiederum führte zu einem weiteren Dilemma: Wenn die
C-Runtime-Bibliothek ein CR+NL einfach stillschweigend in ein einfaches
NL mappt, dann kann man keine Dateien mehr "raw" lesen und schreiben,
also nicht mehr 1:1. Aus diesem Grunde wurde dann für fopen() das b-Flag
eingeführt, also z.B.:
fp = fopen (filename, "rb"); // read binary
Unter Unix/Linux hat dieses B-Flag keine Bedeutung und wird einfach
stillschweigend ignoriert, denn hier liest man ein CR aus einer Datei
immer als '\r' und ein NL als '\n'.
Ist schon lustig, was man alles anstellen muss, um diese damaligen
Design-Entscheidungen heute noch korrekt plattformunabhängig in den
Griff zu bekommen...
Gruß,
Frank