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?
:
Bearbeitet durch User
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?
Ganz schlecht ist: main(...) { ... ENDE : printf(...); } int foo(...) { ... goto ENDE; // Abbruch }
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.
Beispielsweise aus main() Deine File-Einlese-Funktion aufrufen und den Rückgabewert davon auswerten.
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.
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.
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
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.
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.
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
@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.
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...
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.