Forum: PC-Programmierung Wie Programm beenden?


von Paul Schokemöhl (Gast)


Lesenswert?

Ich habe angefangen in C zu programmieren. Auf einem Linux PC mit gcc. 
Ich habe jetzt Funktionen, die Funktionen usw. aufrufen. Wenn ich jetzt 
in irgendeiner aufgerufenen Funktion z.B. eine Datei öffnen will, aber 
der Rückgabewert ist eof und ich möchte das ganze Programm einfach 
printf("Fehlermeldung, dies und das, bla und Blub"); und Abbruch, wie 
mache ich das, ist das schlau?

von Dirk K. (d-k)


Lesenswert?

Paul Schokemöhl schrieb:
> wie
> mache ich das,
1
exit(-1);

> ist das schlau?

Nein.

: Bearbeitet durch User
von Paul Schokemöhl (Gast)


Lesenswert?

Dirk K. schrieb:
> Paul Schokemöhl schrieb:
> wie
> mache ich das,
>
> exit(-1);
>
> ist das schlau?
>
> Nein.

Also nicht schlau. Wie mache ich es, das es schlau ist?

von MaWin (Gast)


Lesenswert?

Ganz schlecht ist:

main(...) {

...
ENDE :
printf(...);
}

int foo(...) {
...
goto ENDE;   // Abbruch
}

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Paul Schokemöhl schrieb:
> ist das schlau?

Kommt drauf an, wenn dein Programm noch sinnvoll ohne die Datei 
weiterarbeiten kann dann nicht, wenn es ohne die Datei zu öffnen 
praktisch nichts brauchbares mehr machen kann, dann schon.

von Hmmm (Gast)


Lesenswert?

Beispielsweise aus main() Deine File-Einlese-Funktion aufrufen und den 
Rückgabewert davon auswerten.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Du rufst einfach in Abhängigkeit vom Rückgabewert der entsprechenden 
Funktion eine Aufräumfunktion auf, die im einfachsten Fall nur den Grund 
auf dem jeweiligen Device ausgibt und anschließend das Programm mit 
einem entsprechenden Rückgabewert beendet. In komplexeren Fällen führt 
die Funktion dann noch Aufräumarbeiten durch.

von Daniel A. (daniel-a)


Lesenswert?

Paul Schokemöhl schrieb:
> Wenn ich jetzt
> in irgendeiner aufgerufenen Funktion z.B. eine Datei öffnen will, aber
> der Rückgabewert ist eof

EOF = End Of File

fopen liefert bei Fehler normalerweise 0 zurück, open und andere posix 
Funktionen meistens -1. Jedenfalls nicht EOF.

Paul Schokemöhl schrieb:
> ich möchte das ganze Programm einfach
> printf("Fehlermeldung, dies und das, bla und Blub"); und Abbruch, wie
> mache ich das, ist das schlau?

Fehlermeldungen würd ich nach stderr (standard error) schreiben:
1
fprintf(stderr, "Fehler!\n");

Oder ins system log:
https://linux.die.net/man/3/syslog

Ich schreibe manchmal auch eine eigene logging Funktion, die dann nach 
stderr oder syslog schreibt.

Beenden kann man es mit mehreren Funktionen, unter anderem: abort exit 
_Exit

Diese tun leicht verschiedene Dinge.

Frameworks, wie z.B. gtk, haben oft nochmal eigene logging Funktionen 
usw., normalerweise mit der Möglichkeit eine eigene logging handler 
funktion zu registrieren.

von Rolf M. (rmagnus)


Lesenswert?

Dirk K. schrieb:
> Paul Schokemöhl schrieb:
>> wie
>> mache ich das,
>
> exit(-1)

Warum gerade -1? Was unterstützt und sinnvoll zum Aufrufer übergeben 
wird, ist systemabhängig. Ich würde positive Werte im Bereich 0 bis 127 
empfehlen, das sollte auf den meisten Systemen gehen.
Wenn man sich auf ISO C beschränken will, das überall funktionieren 
sollte, muss man sich auf EXIT_FAILURE und EXIT_SUCCESS beschränken.

>> ist das schlau?
>
> Nein.

Sagen wir mal so: Für sehr einfache Programme kann man das schon mal 
machen, aber meistens ist es keine gute Idee. Es ist besser, das Problem 
an den Aufrufer zurückzumelden, damit der dann geeignet reagieren kann 
statt einfach das Programm "eigenmächtig" zu beenden.
Man stelle sich vor, das wird mal ein GUI-Programm, und die Routine, die 
versucht, eine Datei zu öffnen, schießt gleich das ganze Programm ab, 
nur weil sie die Datei nicht findet.
Man muss zusätzlich auch bedenken, dass alle Ressourcen, die ggf. in 
anderen Programmteilen genutzt werden, nicht sauber freigegeben werden, 
es sei denn, sie definieren dafür extra einen atexit-Handler.

Daniel A. schrieb:
> Fehlermeldungen würd ich nach stderr (standard error)
> schreiben:fprintf(stderr, "Fehler!\n");
> Oder ins system log:
> https://linux.die.net/man/3/syslog

Es ist für einen Programmieranfänger eher nicht sinnvoll, wenn seine 
ersten Versuche ihre Outputs ins syslog schreiben.

: Bearbeitet durch User
von foobar (Gast)


Lesenswert?

1
    #include <stdlib.h>
2
    #include <string.h>
3
    ...
4
    FILE *fp;
5
    ...
6
    fp = fopen(filename, "r");
7
    if (fp == NULL)
8
    {
9
        fprintf(stderr, "can't open '%s': %s\n", filename, strerror(errno));
10
        exit(EXIT_FAILURE);
11
    }
12
    ...

> Ist das schlau?

Ist quick'n'dirty.  Du gibst so dem Aufrufer keine Chance, den Fehler 
irgendwie zu behandeln - eine untergeordnete Funktion entscheidet, ob 
das Programm weiterläuft oder nicht.

von Programmierer (Gast)


Lesenswert?

Oder direkt eine Sprache verwenden, welche ein systematisches 
Fehlermanagement in Form von Exceptions bietet, sodass man sich das 
Herumhantieren mit Rückgabewerten spart. z.B. C++:
1
#include <stdexcept>
2
#include <stdio.h>
3
4
void foo () {
5
  FILE* f = fopen ("test.txt", "r");
6
  if (!f)
7
    throw std::runtime_error ("Datei konnte nicht geöffnet werden");
8
  
9
  puts ("Mach was mit der Datei");
10
  fclose (f);
11
}
12
13
void bar () {
14
  puts ("bar(). Mache was...");
15
  foo ();
16
  puts ("bar(). Mache nochwas mehr...");
17
}
18
19
int main () {
20
  try {
21
    puts ("main(). Mache was...");
22
    bar ();
23
    puts ("main(). Mache nochwas mehr...");
24
    return 0;
25
  } catch (const std::exception& e) {
26
    fprintf (stderr, "Fehler: %s\n", e.what ());
27
    return 1;
28
  }
29
}

Natürlich wäre es besser hier direkt die C++-Klassen wie std::ifstream 
zu nutzen statt das C-I/O über fopen() & Co. Im Idealfall hat man genau 
eine Stelle mit Fehlerbehandlung, direkt in der main(), und der 
restliche Code sieht so aus als gäbe es keine Fehler, indem man den 
Compiler das Rückwärts-Abwickeln erledigen lässt.

von Daniel A. (daniel-a)


Lesenswert?

Programmierer schrieb:
> Oder direkt eine Sprache verwenden, welche ein systematisches
> Fehlermanagement in Form von Exceptions bietet

Dafür gibt es für C auch Libraries:
https://github.com/guillermocalvo/exceptions4c

von Sebastian S. (amateur)


Lesenswert?

@Paul Schokemöhl
Was Du willst ist eine sehr unfreundliche Art mit dem Benutzer 
umzugehen.

"Du, Du, böser!" und Abbruch ist würglich unfreundlich.

DU bist es, der den Programmfluss kontrolliert.
Eine einfache Meldung: "Dateiende erreicht", von mir aus auch auf 
Auswärts, mit anschließender Abfrage: "Watt nu?" wäre zumindest höflich.

Also komm mal runter von Deinem hohen Ross!

Übrigens: In der heutigen Zeit kann es schwierig werden, die 
Abschlussmeldung einer Konsolenanwendung zu lesen.

von c-hater (Gast)


Lesenswert?

Programmierer schrieb:

> Natürlich wäre es besser hier direkt die C++-Klassen wie std::ifstream
> zu nutzen statt das C-I/O über fopen() & Co. Im Idealfall hat man genau
> eine Stelle mit Fehlerbehandlung, direkt in der main(), und der
> restliche Code sieht so aus als gäbe es keine Fehler, indem man den
> Compiler das Rückwärts-Abwickeln erledigen lässt.

Ja, Exceptions erleichtern einiges. Aber: viele Programmierer benutzen 
sie falsch, vergessen insbesondere, nach oben die eigentliche Ursache 
zurückzugeben, so dass am Ende für den Benutzer eine völlig nutzlose 
Fehlermeldung rauskommt, die ihm keinerlei Anhaltspunkt mehr dazu 
liefert, was eigentlich das Problem war.

Der Extremfall, gerade beim Zugriff auf Dateien, sind da wohl die 
Winzigweich-Programmierer. Im Zweifel wird immer irgendwelcher Bullshit 
mit fehlenden Rechten gemeldet. Wohl weil mal irgensoein Blinder Wichser 
festgestellt hat, dass die meisten Fehler beim Dateizugriff genau darauf 
zurückgehen. Ja, das wird vermutlich sogar stimmen, aber leitet den User 
völlig in die Irre, wenn's mal nicht daran liegt...

von Programmierer (Gast)


Lesenswert?

c-hater schrieb:
> Ja, Exceptions erleichtern einiges. Aber: viele Programmierer benutzen
> sie falsch,

Ja das stimmt leider.

c-hater schrieb:
> vergessen insbesondere, nach oben die eigentliche Ursache
> zurückzugeben,

Viel schlimmer ist das wilde Mischen mit Rückgabecodes und Mengen an 
try-catch-Blöcken; im Idealfall gibt es davon nur sehr wenige. z.B. nur 
einen in der main() bei einfachen Konsolen-Programmen, oder einen pro 
Menüpunkt in einer GUI-Anwendung, welcher dann eine Fehlermeldung 
ausgibt. Leider wird korrektes Exception-Handing bzw. allgemein 
Fehler-Behandlung in vielen Büchern nicht gut erklärt, ist aber IMO 
ziemlich essentiell. In C++ ist das ja auch eng mit RAII (bzw. OOP) 
verknüpft. Das lässt sich hier auch nicht mal eben schnell in einem 
Beitrag erläutern...

c-hater schrieb:
> so dass am Ende für den Benutzer eine völlig nutzlose
> Fehlermeldung rauskommt, die ihm keinerlei Anhaltspunkt mehr dazu
> liefert, was eigentlich das Problem war.

In Java sind dafür Chained Exceptions beliebt; man packt z.B. die 
FileNotFoundException in eine eigene Exception namens 
LogFileNotFoundException sodass sich dann ein strukturierter Backtrace 
ergibt. Leider wird das dann bei der Ausgabe häufig ein ziemlicher 
Datenwust.

c-hater schrieb:
> m Zweifel wird immer irgendwelcher Bullshit
> mit fehlenden Rechten gemeldet.

Das kann Android auch! Da ist's immer "Permission Denied". Ob jetzt die 
DAC-Rechte oder die SELinux-Konfiguration (und welche der tausenden 
dafür zuständigen Zeilen) oder die diversen Prozess-Capabilities schuld 
sind darf man erraten.

von c-hater (Gast)


Lesenswert?

Programmierer schrieb:

> In Java sind dafür Chained Exceptions beliebt; man packt z.B. die
> FileNotFoundException in eine eigene Exception namens
> LogFileNotFoundException sodass sich dann ein strukturierter Backtrace
> ergibt. Leider wird das dann bei der Ausgabe häufig ein ziemlicher
> Datenwust.

So what? Lieber einen Datenwust von einer Fehlermeldung, der aber 
immerhin einen Anhaltspunkt für die Wurzel dieses Wusts gibt, als eine 
"irgendwas ist schief gegangen"-Summary, ggf. noch garniert mit einem 
default, der im konkreten Fall möglicherweise garnicht zutrifft. Was ist 
wohl nützlicher?

Übrigens sind diese Chains natürlich prinzipiell in jeder Sprache 
möglich, die nested Exceptions erlaubt, nicht nur in Java.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.