Freigeben über


Structured Exception Handling (C/C++)

Die strukturierte Ausnahmebehandlung (Structured Exception Handling, SEH) ist eine Microsoft-Erweiterung für C und C++ zur ordnungsgemäßen Behandlung bestimmter außergewöhnlicher Codesituationen (z. B. Hardwarefehler). SEH wird zwar von Windows und Microsoft C++ unterstützt, in C++-Code sollte jedoch besser die C++-Ausnahmebehandlung nach ISO-Standard verwendet werden. Dadurch wird Ihr Code besser portierbar und flexibler. Für die Beibehaltung von bereits vorhandenem Code oder für bestimmte Arten von Programmen kann die Verwendung von SEH allerdings trotzdem erforderlich sein.

Microsoft-spezifisch:

Grammatik

try-except-statement :
__try compound-statement __except ( filter-expression ) compound-statement

try-finally-statement :
__try compound-statement __finally compound-statement

Hinweise

Mit SEH kann sichergestellt werden, dass Ressourcen wie Speicherblöcke und Dateien im Falle einer unerwarteten Beendigung der Ausführung ordnungsgemäß freigegeben werden. Sie können bestimmte Probleme wie unzureichenden Arbeitsspeicher mithilfe von kurzem strukturiertem Code behandeln, in dem keine goto-Anweisungen oder ausführliche Tests von Rückgabecodes verwendet werden.

Die Anweisungen try-except und try-finally, auf die sich dieser Artikel bezieht, sind Microsoft-Erweiterungen für die Programmiersprachen C und C++. Sie unterstützen SEH, indem es Anwendungen ermöglicht wird, die Steuerung eines Programms nach Ereignissen abzurufen, die andernfalls das Beenden der Ausführung zur Folge haben würden. Obwohl SEH mit C++-Quelldateien funktioniert, ist sie nicht ausdrücklich für C++ vorgesehen. Wenn Sie SEH in einem C++-Programm verwenden, das Sie unter Verwendung der Option /EHa oder /EHsc kompilieren, werden Destruktoren für lokale Objekte aufgerufen. Das weitere Ausführungsverhalten entspricht allerdings möglicherweise nicht Ihren Erwartungen. Eine Abbildung finden Sie im Beispiel weiter unten in diesem Artikel. In den meisten Fällen empfiehlt sich anstelle von SEH die Verwendung der C++-Ausnahmebehandlung nach ISO-Standard. Mithilfe der C++-Ausnahmebehandlung können Sie eine bessere Portierbarkeit des Codes sicherstellen, und Sie können Ausnahmen jeglichen Typs behandeln.

Wenn Sie über C-Code verfügen, der SEH verwendet, können Sie ihn mit C++-Code kombinieren, in dem die C++-Ausnahmebehandlung verwendet wird. Informationen hierzu finden Sie unter Behandeln strukturierter Ausnahmen in C++.

Es gibt zwei SEH-Mechanismen:

  • Ausnahmehandler oder __except-Blöcke, die auf Basis des filter-expression-Werts auf die Ausnahme reagieren oder sie schließen können. Weitere Informationen finden Sie unter try-except-Anweisung.

  • Beendigungshandler oder __finally-Blöcke, die immer aufgerufen werden (unabhängig davon, ob eine Ausnahme eine Beendigung verursacht). Weitere Informationen finden Sie unter try-finally-Anweisung.

Diese beiden Arten von Handlern unterscheiden sich zwar, sind allerdings hinsichtlich eines als Entladen des Stapels bekannten Prozesses eng miteinander verknüpft. Wenn eine strukturierte Ausnahme auftritt, wird von Windows der zuletzt installierte Ausnahmehandler gesucht, der gerade aktiv ist. Beim Handler kann eine von drei Möglichkeiten auftreten:

  • Fehler beim Erkennen der Ausnahme und Übergabe der Steuerung an andere Handler (EXCEPTION_CONTINUE_SEARCH)

  • Erkennung und Schließung der Ausnahme (EXCEPTION_CONTINUE_EXECUTION)

  • Erkennung und Behandlung der Ausnahme (EXCEPTION_EXECUTE_HANDLER)

Der Ausnahmehandler, der die Ausnahme erkennt, befindet sich möglicherweise nicht in der Funktion, die bei Auftreten der Ausnahme ausgeführt wurde. Er kann sich auch in einer Funktion befinden, die wesentlich höher im Stapel platziert ist. Die gegenwärtig ausgeführte Funktion sowie alle weiteren Funktionen im Stapelrahmen werden beendet. Während dieses Prozesses wird der Stapel entladen. Das bedeutet: Lokale, nicht statische Variablen von beendeten Funktionen werden aus dem Stapel gelöscht.

Beim Entladen des Stapels ruft das Betriebssystem alle Beendigungshandler auf, die Sie für jede Funktion geschrieben haben. Bei Verwendung eines Beendigungshandlers werden Ressourcen bereinigt, die ansonsten bei einer nicht ordnungsgemäßen Beendigung geöffnet bleiben würden. Wenn Sie einen kritischen Abschnitt erreicht haben, können Sie ihn im Beendigungshandler beenden. Wenn das Programm heruntergefahren wird, können Sie weitere Housekeeping-Aufgaben ausführen (z. B. das Schließen und Entfernen von temporären Dateien).

Nächste Schritte

Beispiel

Wie bereits erwähnt werden Destruktoren für lokale Objekte aufgerufen, wenn SEH in einem C++-Programm verwendet und unter Verwendung der Option /EHa oder /EHsc kompiliert wird. Allerdings entspricht das Verhalten während der Ausführung bei gleichzeitiger Verwendung von C++-Ausnahmen möglicherweise nicht Ihren Erwartungen. Im folgenden Beispiel werden diese unterschiedlichen Verhaltensweisen veranschaulicht:

#include <stdio.h>
#include <Windows.h>
#include <exception>

class TestClass
{
public:
    ~TestClass()
    {
        printf("Destroying TestClass!\n");
    }
};

__declspec(noinline) void TestCPPEX()
{
#ifdef CPPEX
    printf("Throwing C++ exception\n");
    throw std::exception("");
#else
    printf("Triggering SEH exception\n");
    volatile int *pInt = 0x00000000;
    *pInt = 20;
#endif
}

__declspec(noinline) void TestExceptions()
{
    TestClass d;
    TestCPPEX();
}

int main()
{
    __try
    {
        TestExceptions();
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        printf("Executing SEH __except block\n");
    }

    return 0;
}

Wenn Sie /EHsc verwenden, um diesen Code zu kompilieren, aber das lokale Teststeuerungsmakro CPPEX nicht definiert ist, wird der TestClass-Destruktor nicht ausgeführt. Die Ausgabe sieht wie folgt aus:

Triggering SEH exception
Executing SEH __except block

Wenn Sie /EHsc zum Kompilieren des Codes verwenden und CPPEX mithilfe von /DCPPEX definiert wird (damit eine C++-Ausnahme ausgelöst wird), wird der TestClass-Destruktor ausgeführt, und die Ausgabe sieht wie folgt aus:

Throwing C++ exception
Destroying TestClass!
Executing SEH __except block

Wenn Sie /EHa verwenden, um den Code zu kompilieren, wird der TestClass-Destruktor unabhängig davon ausgeführt, ob eine Ausnahme mit einem C++-Standardausdruck vom Typ throw oder mit SEH ausgelöst wurde. In diesem Fall spielt es also keine Rolle, ob CPPEX definiert ist. Die Ausgabe sieht wie folgt aus:

Throwing C++ exception
Destroying TestClass!
Executing SEH __except block

Weitere Informationen finden Sie unter /EH (Ausnahmebehandlungsmodell).

ENDE der Microsoft-spezifischen Informationen

Weitere Informationen

Ausnahmenbehandlung
Schlüsselwörter
<exception>
Modernes C++: Best Practices für Ausnahmen und Fehlerbehandlung
Strukturierte Ausnahmebehandlung