Obsługa wyjątków strukturalnych (C/C++)

Obsługa wyjątków strukturalnych (SEH) to rozszerzenie firmy Microsoft do języków C i C++ do obsługi niektórych wyjątkowych sytuacji kodu, takich jak błędy sprzętowe, bezpiecznie. Mimo że systemy Windows i Microsoft C++ obsługują standard SEH, zalecamy używanie standardowej obsługi wyjątków C++ w standardzie ISO w kodzie C++. Dzięki temu kod jest bardziej przenośny i elastyczny. Jednak aby zachować istniejący kod lub określonego rodzaju programów, nadal może być konieczne użycie SEH.

Specyficzne dla firmy Microsoft:

Gramatyka

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

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

Uwagi

Za pomocą protokołu SEH można upewnić się, że zasoby, takie jak bloki pamięci i pliki, są prawidłowo zwalniane, jeśli wykonanie nieoczekiwanie zakończy się. Można również obsłużyć konkretne problemy — na przykład za mało pamięci — za pomocą zwięzłego kodu ustrukturyzowanego, który nie opiera się na goto instrukcjach ani skomplikowanych testach kodów powrotnych.

Instrukcje try-except i try-finally , o których mowa w tym artykule, to rozszerzenia firmy Microsoft dla języków C i C++. Obsługują SEH, umożliwiając aplikacjom kontrolę nad programem po zdarzeniach, które w przeciwnym razie zakończą wykonywanie. Mimo że SEH współpracuje z plikami źródłowymi języka C++, nie jest specjalnie zaprojektowany dla języka C++. Jeśli używasz SEH w programie C++, który kompilujesz przy użyciu /EHa opcji lub /EHsc , destruktory dla obiektów lokalnych są wywoływane, ale inne zachowanie wykonywania może nie być oczekiwane. Aby zapoznać się z ilustracją, zobacz przykład w dalszej części tego artykułu. W większości przypadków zamiast SEH zalecamy użycie obsługi wyjątków standardu ISO C++. Korzystając z obsługi wyjątków w języku C++, możesz upewnić się, że kod jest bardziej przenośny i można obsługiwać wyjątki dowolnego typu.

Jeśli masz kod C, który używa protokołu SEH, możesz go mieszać z kodem C++, który korzysta z obsługi wyjątków języka C++. Aby uzyskać informacje, zobacz Obsługa wyjątków strukturalnych w języku C++.

Istnieją dwa mechanizmy SEH:

Te dwa rodzaje procedur obsługi są odrębne, ale są ściśle powiązane przez proces znany jako odwijanie stosu. W przypadku wystąpienia wyjątku strukturalnego system Windows wyszukuje ostatnio zainstalowaną procedurę obsługi wyjątków, która jest obecnie aktywna. Procedura obsługi może wykonać jedną z trzech czynności:

  • Nie można rozpoznać wyjątku i przekazać kontrolę do innych procedur obsługi (EXCEPTION_CONTINUE_SEARCH).

  • Rozpoznaj wyjątek, ale go odrzuć (EXCEPTION_CONTINUE_EXECUTION).

  • Rozpoznaj wyjątek i obsłuż go (EXCEPTION_EXECUTE_HANDLER).

Procedura obsługi wyjątków, która rozpoznaje wyjątek, może nie znajdować się w funkcji, która była uruchomiona po wystąpieniu wyjątku. Może to być w funkcji znacznie wyższej na stosie. Obecnie uruchomiona funkcja i wszystkie inne funkcje w ramce stosu są przerywane. W trakcie tego procesu stos jest unwound. Oznacza to, że lokalne zmienne niestatyczne zakończonych funkcji są czyszczone ze stosu.

W miarę odwijania stosu system operacyjny wywołuje wszystkie programy obsługi zakończenia napisane dla każdej funkcji. Korzystając z procedury obsługi zakończenia, należy wyczyścić zasoby, które w przeciwnym razie pozostaną otwarte z powodu nietypowego zakończenia. Jeśli wprowadzono sekcję krytyczną, możesz zamknąć ją w procedurze obsługi kończenia. Gdy program zostanie zamknięty, możesz wykonać inne zadania sprzątania, takie jak zamykanie i usuwanie plików tymczasowych.

Następne kroki

Przykład

Jak wspomniano wcześniej, destruktory dla obiektów lokalnych są wywoływane, jeśli używasz SEH w programie języka C++ i skompiluj je przy użyciu /EHa opcji lub /EHsc . Jednak zachowanie podczas wykonywania może nie być oczekiwane, jeśli używasz również wyjątków języka C++. W tym przykładzie pokazano te różnice behawioralne.

#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;
}

Jeśli używasz /EHsc polecenia do skompilowania tego kodu, ale lokalne makro CPPEX kontroli testów jest niezdefiniowane, TestClass destruktor nie zostanie uruchomiony. Dane wyjściowe wyglądają następująco:

Triggering SEH exception
Executing SEH __except block

Jeśli używasz /EHsc polecenia do kompilowania kodu i CPPEX jest definiowany za pomocą polecenia /DCPPEX (tak, aby zgłaszany był wyjątek języka C++), TestClass destruktor jest uruchamiany, a dane wyjściowe wyglądają następująco:

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

Jeśli używasz /EHa polecenia do skompilowania kodu, destruktor wykonuje, TestClass czy wyjątek został zgłoszony przy użyciu standardowego wyrażenia C++ throw , czy też przy użyciu SEH. Oznacza to, czy CPPEX jest definiowany, czy nie. Dane wyjściowe wyglądają następująco:

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

Aby uzyskać więcej informacji, zobacz /EH (Model obsługi wyjątków).

KONIEC specyficzny dla firmy Microsoft

Zobacz też

Obsługa wyjątków
Słowa kluczowe
<exception>
Błędy i obsługa wyjątków
Obsługa wyjątków strukturalnych (Windows)