it-swarm.com.de

Die Ergebnisse von printf () und system () sind in der falschen Reihenfolge, wenn die Ausgabe in eine Datei umgeleitet wird

Ich habe ein C-Programm, das zu einer ausführbaren Datei namens myprogram kompiliert wird. Dies ist seine Hauptfunktion:

int main(int argc, char ** argv) {
  printf("this is a test message.\n");
  system("ls");

  return 0;
}

Wenn ich myprogram > output.txt in einer Linux-Shell und überprüfen Sie dann output.txt, sehe ich die Ausgabe von ls oben aufgeführt "Dies ist eine Testnachricht."

Ich habe das Gefühl, dass es umgekehrt sein sollte. Warum passiert das und was kann ich tun, damit "Dies ist eine Testnachricht" oben in der Datei "output.txt" angezeigt wird?

Wenn es darauf ankommt, bin ich neu in C und arbeite in einer Befehlszeile.

97
Archr

Standardmäßig ist die Ausgabe an stdout zeilengepuffert, wenn eine Verbindung zu einem Terminal besteht. Das heißt, der Puffer wird geleert, wenn er voll ist oder wenn Sie eine neue Zeile hinzufügen.

Allerdings, wenn stdout nicht mit einem Terminal verbunden ist, wie wenn Sie das umleiten Ausgabe von Ihrem Programm in eine Datei, dann wird stdout vollständig gepuffert. Das bedeutet, dass der Puffer entweder voll oder explizit geleert und tatsächlich geschrieben wird (was passiert, wenn das Programm beendet wird).

Dies bedeutet, dass die Ausgabe eines separaten Prozesses, der von Ihrem Code aus gestartet wurde (wie das, was passiert, wenn Sie system aufrufen), höchstwahrscheinlich zuerst geschrieben wird, da der Puffer dieses Prozesses geleert wird, wenn dieser Prozess endet vor Ihrem eigenen Prozess.

Was passiert bei der Verwendung von Redirection (oder Pipes):

  1. Ihr printf -Aufruf schreibt in den stdout -Puffer.
  2. Die Funktion system startet einen neuen Prozess, der in einen eigenen Puffer schreibt.
  3. Wenn der externe Prozess (der durch Ihren system -Aufruf gestartet wurde) beendet wird, wird sein Puffer geleert und geschrieben. Ihr eigener Puffer in Ihrem eigenen Prozess wird nicht berührt.
  4. Ihr eigener Prozess endet und Ihr stdout -Puffer wird geleert und geschrieben.

Um die Ausgabe in der "richtigen" (oder zumindest erwarteten) Reihenfolge zu erhalten, rufen Sie fflush auf, bevor Sie system aufrufen, um stdout explizit zu leeren. oder rufen Sie setbuf vor jeder Ausgabe auf, um die Pufferung vollständig zu deaktivieren.

143

Dies hängt mit der Ausgabepufferung zusammen. Ich habe es geschafft, das gleiche Verhalten zu reproduzieren. Das Erzwingen des Flushs hat es für mich getan.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char ** argv) {
  printf("this is a test message.\n");
  fflush(stdout);
  system("ls");

  return 0;
}

Vor dem Hinzufügen des Flushs:

$ ./main > foo
$ cat foo
main
main.c
this is a test message.

und danach:

$ ./main > foo
$ cat foo
this is a test message.
foo
main
main.c
18
Aif

Ich vermute, es liegt an der Reihenfolge, in der der Standardpuffer geleert wird, was nicht unbedingt deterministisch ist. Es ist möglich, dass das übergeordnete Element den ls -Prozess erzeugt und seine eigene Standardausgabe erst dann löscht, wenn es zurückkehrt. Es kann sein, dass stdout erst dann tatsächlich gelöscht wird, wenn der Prozess beendet ist.

Fügen Sie nach der printf-Anweisung fflush (stdout) hinzu, und prüfen Sie, ob dadurch die Ausgabe zuerst angezeigt wird.