webentwicklung-frage-antwort-db.com.de

In stdin schreiben und von stdout lesen (UNIX/LINUX/C-Programmierung)

Ich arbeitete an einer Aufgabe, bei der ein Programm einen Dateideskriptor als Argument verwendete (im Allgemeinen vom übergeordneten Element in einem Exec-Aufruf) und aus einer Datei las und in einen Dateideskriptor schrieb. Bei meinen Tests wurde mir klar, dass das Programm funktionieren würde Von der Kommandozeile aus und ohne Fehler, wenn ich 0, 1 oder 2 als Dateideskriptor verwendet habe. Das ergab für mich nur Sinn, dass ich an stdin schreiben und es auf dem Bildschirm anzeigen lassen konnte.

Gibt es eine Erklärung dafür? Ich dachte immer, es gäbe einen gewissen Schutz für stdin/stdout und man kann mit Sicherheit nicht von stdout zu stdin oder fgets fprintf.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
    char message[20];
    read(STDOUT_FILENO, message, 20);
    write(STDIN_FILENO, message, 20);

    return 0;
}
14
Tim

Der Versuch, auf eine Datei zu schreiben, die als schreibgeschützt markiert ist, oder umgekehrt, würde dazu führen, dass write und read -1 zurückgeben und fehlschlagen. In diesem spezifischen Fall sind stdin und stdout tatsächlich dieselbe Datei. Bevor Ihr Programm ausgeführt wird (wenn Sie keine Umleitung durchführen), geht die Shell im Wesentlichen folgendermaßen vor:

  if(!fork()){
       <close all fd's>
       int fd = open("/dev/tty1", O_RDWR);
       dup(fd);
       dup(fd);
       execvp("name", argv);
  }

Stdin, out und err sind also Duplikate desselben Dateideskriptors, die zum Lesen und Schreiben geöffnet wurden.

10
Dave
read(STDIN_FILENO, message, 20); 
write(STDOUT_FILENO, message, 20);

Sollte arbeiten. Hinweis - stdout my be a different place to stdin (auch in der Befehlszeile). Sie können die Ausgabe eines anderen Prozesses als stdin in Ihren Prozess einspeisen oder stdin/stdout als Dateien anordnen.

fprintf/fgets verfügen über einen Puffer, wodurch die Anzahl der Systemaufrufe verringert wird.

2
Ed Heal

Best rate - stdin zeigt, woher die Eingabe kommt, Ihr Terminal und stdout zeigt, wohin die Ausgabe gehen soll, Ihr Terminal. Da beide auf dieselbe Stelle zeigen, sind sie (in diesem Fall) austauschbar.

1
Avery3R

Wenn Sie ein Programm unter UNIX ausführen

myapp < input > output

Sie können/proc/{pid}/fd/1 öffnen und daraus lesen,/proc/{pid}/fd/0 öffnen und darauf schreiben und zum Beispiel output nach input kopieren. (Möglicherweise gibt es einen einfacheren Weg, aber ich weiß, dass es funktioniert.)

Sie können jede Art von Dingen tun, die einfach verwirrend sind, wenn Sie Ihren Verstand darauf verwenden. ;)

1
Peter Lawrey

Wenn Sie eine Nachricht in stdin schreiben möchten, können Sie das aktuelle tty öffnen und den Systemaufruf write aufrufen, um eine Nachricht in dieses fd zu schreiben:

string console_cmd = "hello";
string tty = ttyname(STDIN_FILENO);
int fd = open(tty.c_str(), O_WRONLY);
write(fd, console_cmd.c_str(), console_cmd.size());

Lesen Sie in ähnlicher Weise aus stdout.

0
vinllen

Es ist sehr wahrscheinlich, dass die Dateideskriptoren 0, 1 und 2 sowohl zum Lesen als auch zum Schreiben geöffnet sind (und dass sie sich alle auf dieselbe zugrunde liegende "Beschreibung der geöffneten Datei" beziehen). In diesem Fall funktioniert das, was Sie tun. Aber soweit ich weiß, gibt es keine Garantie, daher könnte es auch nicht funktionieren. Ich glaube, POSIX gibt irgendwo an, dass wenn stderr mit dem Terminal verbunden ist, wenn ein Programm von der Shell aufgerufen wird, es lesbar und beschreibbar sein soll, aber ich kann die Referenz nicht direkt finden.

Im Allgemeinen würde ich davon abraten, jemals von stdout oder stderr zu lesen, es sei denn, Sie suchen nach einem Terminal, von dem Sie ein Kennwort lesen können, und stdin wurde umgeleitet (kein tty). Und ich würde empfehlen, niemals an stdin zu schreiben - es ist gefährlich und Sie könnten eine Datei überladen, von der der Benutzer nicht erwartet hatte, dass sie geschrieben wird!

0
R..