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 | |
---|---|
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
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
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
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 = InputBox("Geben Sie eine Zahl ein") i = (i ^ 2 + 1) / i GibFehler = i Ende: Exit Function Eingabefehler: Select Case Err.Number Case 6 'Überlauf (negativer Wert) Resume Case 11 'Division durch "0" i = 0 Resume Next Case 13 'Typen unverträglich (Text) Resume Ende End Select End Function
In diesem Beispiel wird der User aufgefordert, eine Zahl einzugeben, die in der
Variable i
gespeichert und anschließend dort weiterverarbeitet wird.
Da i
vom Typ Byte ist, kann die Variable aber nur ganzzahlige Werte
von 0 bis 255 annehmen. Das ist nebenbei ein Beispiel für einen versteckten Fehler,
den man leicht übersehen kann. VBA wird einen Fließkommawert in eine Ganzzahl
umrechnen. Alles Debuggen und alle Fehlerroutinen nutzen nichts, wenn man hier
wirklich einen Fließkommawert speichern will.
Gibt der User einen Text ein, kommt es zu einem Typunverträglichkeitsfehler,
weil ja eine Zahl erwartet wird. Bei der Eingabe eines Werts größer 255 oder kleiner
0 kommt es zu einem Überlauffehler, weil der Wert nicht in der Variable gespeichert
werden kann. Und bei der Eingabe von 0
kommt es eine Zeile später zu
einem Fehler, weil dann versucht wird, durch 0
zu teilen. Im Errorhandler
wird nun mit Select Case
zwischen diesen drei Fehlern unterschieden
und unterschiedlich reagiert:
Resume
(ohne weitere Angaben). Das Programm springt zu der Zeile, die
den Fehler verursacht hat, zurück. Der User bekommt also abermals die Möglichkeit
zur Eingabe.i
den Wert 0
zugewiesen und wegen Resume Next
anschließend die Zeile im normalen
Programmcode abgearbeitet, welche auf den Fehler folgt.Resume Ende
wird zu einer weiteren Zeilenmarke
namens Ende:
gesprungen. Da hier auf Ende:
nur noch
Exit Function
folgt, gibt die Funktion also nichts zurück.