Fehlerbehandlungsroutinen

Fehlermeldungen sind eine Sache, die schon so manchen Programmierer an den Rand des Wahnsinns getrieben haben: Mal tritt der Fehler auf, dann wieder nicht... Jedes Projekt erreicht schnell einen Punkt, an dem sich logische Fehler verstecken können, die sich programmtechnisch nur schwer erschließen oder gar ganz entziehen. Es ist aber möglich, Fehler aufzufangen und das Programm darauf reagieren zu lassen.

Sub Kehrwert()
Dim i As Long

For i = -10 To 10
    Debug.Print 1 / i
Next

End Sub

Microsoft Visual Basic
exclamation Laufzeitfehler '11':
Division durch Null
 

Im obigen Beispiel ist der Fehler noch leicht erkennbar: Es sollen für alle Zahlen von -10 bis 10 die Kehrwerte ausgegeben werden, also 1 geteilt durch die jeweilige Zahl. Dummerweise erreicht die Schleife irgendwann auch den Wert 0, und eins geteilt durch null ist mathematisch nicht definiert.

Nicht immer lässt sich so leicht wie hier erkennen, welche Werte eine Variable annehmen wird. Wenn z. B. Werte vom User direkt eingegeben werden können, wird es immer besonders kritisch.

Natürlich sollte es zum guten Stil gehören, kritische Situationen wie Division durch 0 oder knapp bemessene Datentypen von vornherein zu vermeiden. Ganz verhindern kann man sie allerdings nicht. Für diese Fälle sind Fehlerbehandlungsroutinen, neudeutsch Errorhandler vorgesehen: Code, der dann aktiv wird, wenn ein Fehler auftaucht.

Eine Fehlerbehandlungsroutine wird mit On Error „eingeschaltet“ und überwacht dann den folgenden Code. Solange kein Fehler auftritt, hat sie keine Auswirkungen. Erst im Fehlerfall wird sie aktiv. Konkret überwacht die Fehlerbehandlung das Raise-Ereignis des Err-Objekts. Sobald es eintritt, ändert sich die Fehlernummer des Err-Objekts - man sagt, „es wird ein Fehler ausgeworfen“. „Division durch Null“ hat z. B. stets die Fehlernummer „11“.

On Error Resume Next

On Error Resume Next ist die „primitivste“ Form der Fehlerbehandlung: Fehlerhafte Codezeilen, die nach dieser Anweisung auftauchen, werden einfach ignoriert, der Code wird in der nächsten Zeile nach dem Fehler weiter abgearbeitet.

Sub Kehrwert()
Dim i As Long

On Error Resume Next

For i = -10 To 10
    Debug.Print 1 / i
Next

End Sub

Dieser Code arbeitet die Schleife mit den Werten von -10 bis -1 ab, überspringt dann den Wert 0, und macht anschließend mit 1 bis 10 weiter.

On Error GoTo

On Error GoTo ist die übliche Art der Fehlerbehandlung. Wer schon andere, zumeist sehr viel ältere Basicdialekte kennengelernt hat, dem wird das GoTo darin bekannt vorkommen - und wahrscheinlich übel aufstoßen. Zu Recht. GoTo lässt sich auch in VBA als Zeilenmarke beliebig einsetzen. Dummerweise erzeugt GoTo fürchterlichen „Spagetticode“, also Code, den man nicht mehr überblicken kann. Deswegen wurde die Beschreibung von GoTo im Abschnitt Ablaufsteuerung bewusst ausgelassen, und es gibt auch keinen Grund, es jemals einzusetzen. Für Fehlerbehandlungsroutinen hat sich allerdings eine Variante von GoTo durchgesetzt, und wenn es nur dafür verwendet wird, spricht auch nichts dagegen.

Bei einer Zeilenmarke handelt es sich um ein beliebiges Wort oder Zahlen, gefolgt von einem Doppelpunkt. Eine Zeilenmarke muss innerhalb der Prozedur eindeutig sein. Mit On Error GoTo Zeilenmarke wird eine Fehlerbehandlungsroutine eingerichtet, die innerhalb der Prozedur bei einem Fehler die Bearbeitung des „normalen“ Codes abbricht und stattdessen ab der Zeilenmarke fortsetzt. Üblicherweise endet der „normale“ Code mit Exit Sub bzw. Exit Function, gefolgt von der Zeilenmarke der Fehlerbehandlungsroutine.

Function GibFehler() As Double
Dim i As Double

On Error GoTo Eingabefehler

i = 1 / InputBox("Geben Sie eine Zahl ein")

GibFehler = i

Exit Function

Eingabefehler:
GibFehler = 0

End Function

Hier wird der User aufgefordert, eine beliebige Zahl einzugeben. Die Funktion gibt deren Kehrwert zurück und endet bei Exit Function. Allerdings könnte der User ja auch „0“ oder einen Text eingeben. Damit wird ein Fehler erzeugt, und die Funktion wird ab der Zeilenmarke Eingabefehler: weiter ausgeführt. Es wird also „0“ zurückgegeben.

Es ist auch möglich, innerhalb einer Prozedur mehrere Errorhandler zu nutzen. Eine aktive Fehlerbehandlungsroutine wird mit On Error Goto 0 wieder ausgeschaltet.

On Error GoTo Fehler1
'irgendein Code

On Error GoTo 0
'Code ohne Errorhandler

On Error GoTo Fehler2
'noch mehr Code

Exit Sub

Fehler1:
'Hier steht ein Errorhandler

Fehler2:
'Hier steht ein anderer Errorhandler

Resume

Ein Errorhandler wird bis zum Ende der Prozedur bzw. einer Exit-Anweisung abgearbeitet. Mit Resume kann aber auch wieder in den normalen Code zurückgesprungen werden.

Function GibFehler()
Dim i As Byte

On Error GoTo Eingabefehler

i = 1
i = 1 / InputBox("Geben Sie eine Zahl ein")

GibFehler = i

Ende:
Exit Function

Eingabefehler:
Select Case Err.Number
    Case 6  'Überlauf (negativer Wert)
        Resume
    Case 11 'Division durch Null
        Resume Next
    Case 13 'Typen unverträglich (Text)
        Resume Ende
End Select

End Function

In diesem Beispiel ist i vom Typ Byte. Gibt der User eine positive Zahl größer 1 ein, wird stets 0 ausgegeben, da das Ergebnis der Division in einer Bytevariable gespeichert wird. Das ist nebenbei ein nettes Beispiel für einen versteckten Fehler, den man leicht übersehen kann. Alles Debuggen und alle Fehlerroutinen nutzen nichts, wenn wir hier wirklich einen Kehrwert speichern wollten: Am Testen des Codes führt eben nie ein Weg vorbei.

Gibt der User dagegen etwas anderes als eine positive Zahl ein, entsteht ein Fehler. Mit Select Case wird zwischen drei verschiedenen Fehlern unterschieden und unterschiedlich reagiert: