Tratamento de exceções estruturado (C/C++)

O SEH (tratamento de exceção estruturado) é uma extensão da Microsoft para C e C++ para lidar com determinadas situações de código excepcionais, como falhas de hardware, normalmente. Embora o Windows e o Microsoft C++ ofereçam suporte ao SEH, recomendamos o uso do tratamento de exceções no C++ padrão ISO para códigos em C++. Isso torna seu código mais portátil e flexível. Entretanto,para manutenção de código existente ou em tipos específicos de programas, você ainda pode precisar do SEH.

Específico da Microsoft:

Gramática

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

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

Comentários

Com o SEH, é possível garantir que os recursos, como blocos e arquivos de memória, sejam lançados corretamente se a execução for finalizada inesperadamente. Você também pode controlar problemas específicos como, por exemplo, memória insuficiente, usando um código estruturado e conciso que não confia em instruções goto ou em testes elaborados de códigos de retorno.

As instruções try-except e try-finally mencionadas neste artigo são extensões da Microsoft para as linguagens C e C++. Elas oferecem suporte ao SEH permitindo que os aplicativos controlem um programa após os eventos que, caso contrário, finalizariam a execução. Ainda que o SEH funcione com arquivos de origem C++, ele não é projetado especificamente para C++. Se você usar o SEH em um programa C++ compilado com o uso da opção /EHa ou /EHsc, os destruidores de objetos locais são chamados, mas outros comportamentos de execução podem não ser os esperados. Para obter uma ilustração, consulte o exemplo posteriormente neste artigo. Na maioria dos casos, em vez do SEH, nós recomendamos que você use o padrão ISO de manipulação de exceção C++. Usando o tratamento de exceções C++, é possível garantir que o seu código seja mais portátil e tratar exceções de qualquer tipo.

Se você tiver um código C que usa SEH, poderá misturá-lo com o código C++ que usa tratamento de exceção C++. Para obter informações, consulte Tratar exceções estruturadas no C++.

Existem dois mecanismos de SEH:

Esses dois tipos dos manipuladores são distintos, mas estão intimamente relacionados por meio de um processo conhecido como deslocamento da pilha. Quando uma exceção estruturada ocorre, o Windows procura o manipulador de exceção recentemente instalado que está atualmente ativo. O manipulador pode executar uma de três ações:

  • Não reconhecer a exceção e não passar o controle para outros manipuladores (EXCEPTION_CONTINUE_SEARCH).

  • Reconhecer a exceção, mas ignorá-la (EXCEPTION_CONTINUE_EXECUTION).

  • Confirmar a exceção e manipulá-la (EXCEPTION_EXECUTE_HANDLER).

O manipulador de exceções que reconhece a exceção pode não estar na função em execução no momento da exceção. Ele pode estar em uma função muito mais alta na pilha. A função em execução no momento e quaisquer outras funções no quadro de pilhas são terminadas. Durante esse processo, a pilha é deslocada. Ou seja, variáveis não estáticas locais de funções terminadas são desmarcadas da pilha.

Como o sistema operacional desenrola a pilha, ele chama todos os manipuladores de término escritos para cada função. Usando um manipulador de término, você limpa os recursos que, caso contrário, permaneceriam abertos devido a um encerramento anormal. Se você tiver entrado em uma seção crítica, será possível sair dela no manipulador de término. Quando o programa estiver prestes a fechar, será possível executar outras tarefas de manutenção como fechar e remover os arquivos temporários.

Próximas etapas

Exemplo

Conforme mencionado anteriormente, os destruidores de objetos locais são chamados se você usar SEH em um programa C/C++ e compilar usando a opção /EHa ou /EHsc. No entanto, o comportamento durante a execução pode não ser o esperado se você também estiver usando exceções C++. Esse exemplo demonstra essas diferenças de comportamento.

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

Se você usar /EHsc para compilar esse código, mas a macro de controle de teste local CPPEX estiver indefinida, o destruidor TestClass não é executado. A saída tem esta aparência:

Triggering SEH exception
Executing SEH __except block

Se você usar /EHsc para compilar o código e CPPEX estiver definido por meio do uso de /DCPPEX (de modo que uma exceção seja gerada), o destruidor TestClass é executado, e a saída é parecida com essa:

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

Se você usar /EHa para compilar o código, o destruidor TestClass executará se uma exceção foi lançada usando uma expressão throw C++ padrão ou usando SEH. Ou seja, se CPPEX está definido ou não. A saída tem esta aparência:

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

Para obter mais informações, consulte /EH (Modelo de tratamento de exceções).

FIM Específico da Microsoft

Confira também

Manuseio de exceção
Palavras-chave
<exception>
Erros e tratamento de exceções
Tratamento de exceções estruturado (Windows)