Guter Stil für "Fehlerbehandlungen"?
Verfasst: 30.12.2022, 22:57
Abend liebe ZFX'ler :-)
Erfreulicherweise macht mein BMP-Parser gute Fortschritte. Nun gibt es verschiedene Stellen in meinem Code, an welchen ich auf "Ausnahmen" reagieren muss - oder zumindest sollte. Zum Einen versuche ich ein File zu öffnen und reserviere im Anschluss mittels malloc dynamisch Speicher. Beides kann ja bekanntermassen auch mal fehlschlagen kann. Zum Anderen sind da noch diverse "Sonderfälle" in den BMP-Spezifikationen, die mein Parser nicht abdeckt.
Kurzum: ich muss an etlichen Stellen im Code auf allfällige Ausnahmen reagieren und kann nur fortfahren, wenn diese ausbleiben.
An diesem Punkt hat sich dann die Frage aufgedrängt, was ein guter (sinnvoller) Stil sein könnte, um den Code weiterhin gut leserlich und einfach erweiterbar zu halten.
Grob umrissen sind mir dazu vier verschiedene Methoden eingefallen. Mich würde an dieser Stelle interessieren, was ihr davon haltet und wie ihr solche, oder ähnliche Situationen implementiert.
(Es ist übrigens ein reines C Projekt)
Möglichkeit 1 - if else Verschachtelungen
Es wird mittels if-Statement geprüft ob alles ok ist. Die Fortsetzung des Programmablaufs befindet sich dann innerhalb eines if-Blocks - die Fehlerbehandlung innerhalb des else-Blocks (oder andersrum).
Dadurch weist der Code mehrere Verschachtelungs-Ebenen auf.
Aufgeräumt wird in den entsprechenden if-else-Blöcken.
Möglichkeit 2 - setzen einer error oder goOn Variable
Jeder Code-Abschnitt ist von einem if-Statement eingeschlossen, das eine error- oder goOn Variable prüft. Geht etwas schief, wird die Variable entsprechend geändert und damit alle weiteren Abschnitte in Folge übersprungen.
Somit weist der Code grundsätzlich nur eine Verschachtelungs-Ebene auf.
Aufgeräumt (fclose(), free(), etc.) wird dann am Schluss - an einer einzelnen, zentralen Stelle.
Möglichkeit 3 - Vorzeitiges return (an mehreren Stellen)
Ein if-Statement wird geprüft. Geht etwas schief, wird aufgeräumt und mittels return frühzeitig zurückgekehrt. Somit gäbe es nicht nur ein einzelnes return, sondern mehrere.
Möglichkeit 4 - Mittels goto die hinfälligen Code-Abschnitte überspringen
Ein if-Statement wird geprüft. Geht etwas schief, wird mittels goto zu einer Aufräum-und-return Marke gesprungen. Diese ist am Ende der Funktion platziert. Das goto scheint ja keinen sonderlich guten Ruf zu geniessen, doch vielleicht wäre es hier eine adäquate Lösung?
Was denkt ihr dazu? Gibt es vielleicht eine Methode, die in der Praxis häufiger verwendet wird, da sie bestimmte Vorteile bietet?
Ergänzend wollte ich noch, je nach auftretendem Fehler ein string literal zurückgeben. In diesem Zusammenhang habe ich dann realisiert, dass ich mir gar nicht sicher bin, ob ich das so machen darf, wie ich mir das vorgestellt hatte:
Fall 1:
Fall 2:
Fall 3:
Die string literale liegen ja eigentlich alle auf dem Data-Segment, oder? Da dieses ja unabhängig und beständig ist (nicht wie lokale Variablen einer Funktion auf dem Stack), müssten eigentlich somit alle drei Fälle in Ordnung sein. Oder übersehe ich da vielleicht etwas?
Gruss und guten Rutsch ins neue Jahr! :-)
LG, starcow
Erfreulicherweise macht mein BMP-Parser gute Fortschritte. Nun gibt es verschiedene Stellen in meinem Code, an welchen ich auf "Ausnahmen" reagieren muss - oder zumindest sollte. Zum Einen versuche ich ein File zu öffnen und reserviere im Anschluss mittels malloc dynamisch Speicher. Beides kann ja bekanntermassen auch mal fehlschlagen kann. Zum Anderen sind da noch diverse "Sonderfälle" in den BMP-Spezifikationen, die mein Parser nicht abdeckt.
Kurzum: ich muss an etlichen Stellen im Code auf allfällige Ausnahmen reagieren und kann nur fortfahren, wenn diese ausbleiben.
An diesem Punkt hat sich dann die Frage aufgedrängt, was ein guter (sinnvoller) Stil sein könnte, um den Code weiterhin gut leserlich und einfach erweiterbar zu halten.
Grob umrissen sind mir dazu vier verschiedene Methoden eingefallen. Mich würde an dieser Stelle interessieren, was ihr davon haltet und wie ihr solche, oder ähnliche Situationen implementiert.
(Es ist übrigens ein reines C Projekt)
Möglichkeit 1 - if else Verschachtelungen
Es wird mittels if-Statement geprüft ob alles ok ist. Die Fortsetzung des Programmablaufs befindet sich dann innerhalb eines if-Blocks - die Fehlerbehandlung innerhalb des else-Blocks (oder andersrum).
Dadurch weist der Code mehrere Verschachtelungs-Ebenen auf.
Aufgeräumt wird in den entsprechenden if-else-Blöcken.
Möglichkeit 2 - setzen einer error oder goOn Variable
Jeder Code-Abschnitt ist von einem if-Statement eingeschlossen, das eine error- oder goOn Variable prüft. Geht etwas schief, wird die Variable entsprechend geändert und damit alle weiteren Abschnitte in Folge übersprungen.
Somit weist der Code grundsätzlich nur eine Verschachtelungs-Ebene auf.
Aufgeräumt (fclose(), free(), etc.) wird dann am Schluss - an einer einzelnen, zentralen Stelle.
Möglichkeit 3 - Vorzeitiges return (an mehreren Stellen)
Ein if-Statement wird geprüft. Geht etwas schief, wird aufgeräumt und mittels return frühzeitig zurückgekehrt. Somit gäbe es nicht nur ein einzelnes return, sondern mehrere.
Möglichkeit 4 - Mittels goto die hinfälligen Code-Abschnitte überspringen
Ein if-Statement wird geprüft. Geht etwas schief, wird mittels goto zu einer Aufräum-und-return Marke gesprungen. Diese ist am Ende der Funktion platziert. Das goto scheint ja keinen sonderlich guten Ruf zu geniessen, doch vielleicht wäre es hier eine adäquate Lösung?
Was denkt ihr dazu? Gibt es vielleicht eine Methode, die in der Praxis häufiger verwendet wird, da sie bestimmte Vorteile bietet?
Ergänzend wollte ich noch, je nach auftretendem Fehler ein string literal zurückgeben. In diesem Zusammenhang habe ich dann realisiert, dass ich mir gar nicht sicher bin, ob ich das so machen darf, wie ich mir das vorgestellt hatte:
Fall 1:
Code: Alles auswählen
const char* msg;
...
if(1)
{
msg = "ZFX"; // string literal nicht im gleichen Block (scope) wie der pointer msg
}
Code: Alles auswählen
void foo(const char** msg)
{
*msg = "Alles hat geklappt"; // string literal mit "Herkunft" aus einer anderen Funktion als der pointer msg
return;
}
Code: Alles auswählen
const char* foo(void)
{
return "Ist das noch legal?"; // Adresse des string literals mit "Herkunft" aus einer anderen Funktion
}
Gruss und guten Rutsch ins neue Jahr! :-)
LG, starcow