2016-12-18 6 views
2

Ich habe ein einfaches C-Programm mit der Lesefunktion und ich verstehe die Ausgabe nicht.C Einlesen in bash: stdin und stdout

//code1.c 
#include <unistd.h> 
#include <stdio.h> 
#include <fcntl.h> 
int main() 
{ 

    int r; 
    char c; // In C, char values are stored in 1 byte 

    r = read (0, &c, 1); 

    // DOC: 
    //ssize_t read (int filedes, void *buffer, size_t size) 
    //The read function reads up to size bytes from the file with descriptor filedes, storing the results in the buffer. 
    //The return value is the number of bytes actually read. 

    // Here: 
    // filedes is 0, which is stdin from <stdio.h> 
    // *buffer is &c : address in memory of char c 
    // size is 1 meaning it will read only 1 byte 

    printf ("r = %d\n", r); 

    return 0; 
} 

Und hier ist ein Screenshot des Ergebnisses:

Screenshot of program executio

ich dieses Programm 2-mal lief, wie oben gezeigt, und tippte „a“ für den ersten Versuch und „aecho hallo“ für die zweiter Versuch.

Wie ich versuche, um die Ergebnisse zu erklären:.

  1. Wenn read genannt wird, sorgt dafür, dass stdin geschlossen und öffnet es (aus meiner Sicht, warum Sie sollte es nur lesen ich nicht weiß, warum es es öffnet).
  2. Ich tippe "Aecho Hi" in die Bash und drücke Enter.
  3. read hat Priorität, stdin zu verarbeiten und liest das erste Byte von "aecho hi": "a".
  4. Ich bekomme die Bestätigung, dass read 1 Byte mit dem printf verarbeitet hat.
  5. a.out ist beendet und wird beendet.
  6. Irgendwie werden die restlichen Daten in stdin in bash (dem Vater meines Programms) verarbeitet und gehen zu stdout, die es ausführt, und aus irgendeinem Grund wurde das erste Byte von read gelöscht.

Dies ist alles hypothetisch und sehr verschwommen. Jede Hilfe zu verstehen, was passiert ist, wäre sehr willkommen.

+0

'stdin' wird geöffnet, wenn das Programm startet, nicht nur wenn' read() 'aufgerufen wird. Der Rest Ihrer Erklärungen ist korrekt. – alk

+0

'stdin' ist kein" * process * ", sondern ein Stream, wie' stdout' auch. – alk

+0

"* geht zu stdout *" nicht wirklich, die Shell (bash hier) echoet, was sie über 'stdin' nach' stdout' gelesen hat, führt dann aus was sie liest ('echo hi') und druckt/schreibt das Ergebnis (' hi ') zu' stout '. – alk

Antwort

1

Wenn Sie an Ihrem Terminalemulator eingeben, schreibt er Ihre Tastenanschläge in eine "Datei", in diesem Fall einen speicherinternen Puffer, der dank des Dateisystems genau wie jede andere Datei auf der Festplatte aussieht.

Jeder Prozess erbt 3 geöffnete Dateizugriffsnummern von seinem übergeordneten Element. Wir sind an einem von ihnen hier interessiert, Standardeingabe.Das Programm, das vom Terminal-Emulator ausgeführt wird (hier bash), wird als Standardeingabe der im ersten Absatz beschriebene Speicherzwischenspeicher angegeben.

a.out, wenn sie von bash, laufen auch empfängt diese gleiche Datei wie seine Standardeingabe. Denken Sie daran: bash und a.out lesen aus der gleichen, bereits geöffneten Datei.

Nachdem Sie a.out ausgeführt haben, read Blöcke, weil seine Standardeingabe leer ist. Wenn Sie aecho hi<enter> eingeben, schreibt das Terminal diese Zeichen in den Puffer (<enter> wird zu einem einzelnen Zeilenvorschubzeichen). a.out nur Anfragen ein Zeichen, so wird es a und lässt den Rest der Zeichen in der Datei. (Oder genauer gesagt, wird der Dateizeiger noch am e zeigt nach a gelesen wird.)

Nach a.out abgeschlossen ist, bash versucht, aus der gleichen Datei zu lesen. Normalerweise ist die Datei leer (d. H. Der Dateizeiger befindet sich am Ende der Datei), so dass bash auf einen anderen Befehl wartet. In diesem Fall ist jedoch bereits eine Eingabe verfügbar: echo hi\n. bash liest das jetzt genauso, als hätten Sie es eingegeben nacha.out abgeschlossen.

1

Überprüfen Sie this. Wie Alk andeutet, sind Stdin und Stdout bereits mit dem Programm geöffnet. Nun müssen Sie verstehen, wenn Sie Folgendes eingeben:

aecho hi 

und drücken kehrt der stdin Puffer mit all diesen Buchstaben gefüllt ist (und Raum) - und wird so lange sein, wie Sie es nicht spülen. Wenn das Programm beendet wird, ist der stdin-Puffer immer noch voll, und Ihr Terminal verarbeitet automatisch einen Schreibvorgang in stdin, indem es auf stdout zurückspringt - das sehen Sie am Ende - Ihre Shell liest stdin.

Jetzt, wie Sie darauf hinweisen, Ihr Code "drückt Return" für Sie sozusagen - in der ersten Ausführung eine leere Shell-Zeile hinzufügen, und in der zweiten Ausführung echo hi. Aber Sie müssen sich erinnern, Sie gedrückten Rückkehr, so "\ n" ist im Puffer! Um explizit, in Sie tatsächlich getippt:

aecho hi\n 

Sobald Ihr Programm beendet die Shell die verbleibenden Zeichen im Puffer liest, einschließlich der Rückkehr, und das ist, was Sie sehen!

+0

Aber warum hat das "a" von "aecho hi" gelesen? Und in der ersten Ausführung ist der Puffer leer (unter der Annahme, dass das "a" geleert wurde). Trotzdem führt es immer noch einen leeren Befehl aus. – shrimpdrake

+0

Ich folge nicht - in der ersten Ausführung hast du 'a' eingegeben. Das füllte den Puffer mit 'a', das liest, dann spült (ja liest, entfernt, was es liest). So funktioniert das Lesen (wie die meisten Dinge, die gelesen werden, möchten Sie, dass der nächste Anruf den nächsten Buchstaben liest, nicht den gleichen - scanf, get, etc ...). Dann gibt es noch das "\ n" - Return! Ich werde meine Antwort bearbeiten Ich habe es vergessen. – kabanus

+0

Über das "\ n": Ich bin "gezwungen", Enter zu drücken, um zu sagen, dass ich diese Eingabe bevölkert habe, wenn ich umgehen konnte, dass das Programm einfach den Rest des Textes in stdout setzen würde, den ich bearbeiten könnte in bash (da es noch nicht mit einem \ n ausgeführt wurde). Wie mache ich das ? – shrimpdrake