17. Grundlagen der Fehlerbehandlung Fehlersituationen Nenner im Bruch ist 0 / Division durch 0 Datei nicht vorhanden Unzulässige Eingabe von Daten (z.B. Zeichen statt Zahl) Adressierungsfehler (Pointer/Arrays) Nicht existierendes Zeichen im string (z.B. str.at(12) für str=“text“) Speicher reicht nicht (z.B. für Array) Falsche Eingabe durch Benutzer Konsequenz: falsche Ergebnisse oder Programmabsturz Dr. Norbert Spangler / Grundlagen der Informatik 27.05.2007 2 Fehlerbehandlung/Techniken Bisher verwendete Techniken: „konventionelle Methode“ Plausibilitätskontrolle von (Eingabe-)Daten/Ergebnissen -> return x Definiertet Abbruch Assert-Befehl Neu Exception-Handling Dr. Norbert Spangler / Grundlagen der Informatik 27.05.2007 3 17.1 Konventionelle Methode Man überprüft mittels eines if-Befehls einer passend geschriebenen Funktion ob ein Fehler vorliegt. Danach wird dies der „anfordernden Funktion“ mitgeteilt mittels eines returncodes (z.B. -1 für Fehler / 0 für OK ) eine Fehlermeldung am Bildschirm erzeugt und eine Benutzereingabe angefordert eine Fehlermeldung am Bildschirm erzeugt und das Programm abgebrochen. Dr. Norbert Spangler / Grundlagen der Informatik 27.05.2007 4 konventionelle Methode Aufruf einer Funktion mit Rückgabewert vom Typ int int ergebnis = funktion(.......); if ( ergebnis==0 ) // alles OK else // dann wars ein Fehler Durch unterschiedliche Rückgabewerte kann man auch unterschiedliche Fehlerarten anzeigen. Oder vom Typ bool if ( funktion(.......) ) // alles OK else // dann wars ein Fehler Dr. Norbert Spangler / Grundlagen der Informatik 27.05.2007 5 17.2 Assert-Befehl Benötigt <assert.h> assert ( boolscher Ausdruck) Es soll sichergestellt werden, dass der boolsche Ausdruck true ist. Falls der Ausdruck false ist, wird eine Systemfehlermeldung erzeugt und das Programm beendet. Beispiel: Bruch::Bruch(string p_bezeichnung,int p_zaehler, int p_nenner) // Konstruktor { assert(p_nenner>0); // nenner muss > 0 sein bezeichnung=p_bezeichnung; zaehler=p_zaehler; nenner=p_nenner; // }; Dr. Norbert Spangler / Grundlagen der Informatik 27.05.2007 6 Assert-Befehl/Aufruf Dr. Norbert Spangler / Grundlagen der Informatik 27.05.2007 7 17.3 Exception-Handling Grundidee Trennung des normalen Programablaufs, der überwacht werden soll, von dem Teil für die Fehlerbehandlung Programmteil unter Überwachung Meldung (throw) Programmteil zur Fehlerbehandlung Meldung erfolgt durch die throw-Anweisung, welche ein sogenanntes Fehlerobjekt in den Programmteil zur Fehlerbehandlung „wirft“. Das Fehlerobjekt kann von beliebigem Typ sein also int, string, ein Klassenobjekt usw. Dr. Norbert Spangler / Grundlagen der Informatik 27.05.2007 8 Exception-Handling/Ablauf 1. Kennzeichnung des Blocks, welcher Meldungen auslösen darf try-Block 2. Anschliessend folgen ein oder mehrere Exception-Handler, welche die „ausgeworfenen“ Fehlerobjekte in Empfang nehmen und abarbeiten. Jeder Exception-Handler steht in einem catch-Block d.h. es folgen ein oder mehrere catch-Blöcke auf den try-Block; 3. Nach dem letzten catch-Block get es „ohne Exception-Handling“ weiter. Dr. Norbert Spangler / Grundlagen der Informatik 27.05.2007 9 Exception-Handling/try-Block try-Block try { // hier stehen die Befehle, die Meldungen erzeugen dürfen // mittels eines throw fehlerobjekt; } Beispiele für throw Anweisung: throw “Fehler aufgetreten“; // Typ ist char* throw i; // Typ ist int Dr. Norbert Spangler / Grundlagen der Informatik 27.05.2007 10 Exception-Handling/catch-Block catch-Block catch (objekttyp name) { // hier wird festgelegt, was mit Fehlern, die ein Fehlerobjekt // vom Typ objekttyp „werfen“, geschehen soll } Jeder catch-Block steht für einen Typ. Es kann mehrere catch-Blöcke mit unterschiedlichen Typen geben. Beispiel: catch ( char* text) { cout <<text; return 1; } Dr. Norbert Spangler / Grundlagen der Informatik 27.05.2007 11 Exception-Handling/catch-Block Der Exeption-Handler catch (...) { // Aktionen } reagiert auf alle anderen ausgeworfenen Fehlerobjekt-Typen, z.B. auf solche, die von Systemmeldungen kommen. Dr. Norbert Spangler / Grundlagen der Informatik 27.05.2007 12 Exception-Handling/Beispiel #include <iostream> #include <fstream> using namespace std; int main() { int i,z,n; fstream out("ausgabe.txt",ios::out); // try-Block try { fstream ein; ein.open("eingabe.txt",ios::in); if ( ein.fail() ) throw "eingabe.txt kann nicht geoeffnet werden"; i=0; ein >> i>>z>>n; while (!ein.eof() ) { i++; if ( ein.fail() ) throw i; //Verarbeitung out<< i<<z; ein >> i>>z>>n; } ein.close(); if ( ein.fail() ) throw "eingabe.txt kann nicht geschlossen werden"; // catch-Block catch (char * str) { cout <<str<<endl; return -1; } catch (int nr) { cout <<" Fehler in Zeile "<<nr<<endl; return nr; } catch (...) { cout <<" unbekannter Fehler"<<endl; } // hier gehts weiter cout << " das wars"<<endl; return 0; } } Dr. Norbert Spangler / Grundlagen der Informatik 27.05.2007 13 Exception-Handling/Beispiel Wenn die Datei nicht da ist, wird das fail-Bit gesetzt. Dies führt dann zum ersten throw – Typ char* . Ist in der Datei beispielsweise ein Buchstabe wird das fail-Bit gesetzt. Dies führt dann zum throw – Typ int. Dr. Norbert Spangler / Grundlagen der Informatik 27.05.2007 14