Instrucción try-except

La instrucción try-except es una extensión específica de Microsoft que admite el manejo estructurado de excepciones en los lenguajes C y C++.

    // . . .
    __try {
        // guarded code
    }
    __except ( /* filter expression */ ) {
        // termination code
    }
    // . . .

Grammar

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

Comentarios

La instrucción try-except es una extensión de Microsoft para los lenguajes C y C++. Permite que las aplicaciones de destino obtengan control cuando se producen eventos que normalmente finalizan la ejecución del programa. Estos eventos se denominan excepciones estructuradas, o bien excepciones para abreviar. El mecanismo que trata estas excepciones se denomina control estructurado de excepciones (SEH).

Para obtener información al respecto, vea la instrucción try-finally.

Las excepciones pueden estar basadas en hardware o software. El control estructurado de excepciones es útil incluso cuando las aplicaciones no se pueden recuperar completamente de las excepciones de hardware o software. SEH permite mostrar información de error y capturar el estado interno de la aplicación para ayudar a diagnosticar el problema. Es especialmente útil para problemas intermitentes que no son fáciles de reproducir.

Nota:

El control de excepciones estructurado funciona con Win32 para archivos de código fuente de C y C++. Sin embargo, no está diseñado específicamente para C++. Para asegurarse de que el código será más portable, use el control de excepciones de C++. Además, el control de excepciones de C++ es más flexible, ya que puede controlar excepciones de cualquier tipo. Para los programas de C++, le recomendamos que utilice el manejo de excepciones nativo de C++: instrucciones try, catch y throw.

La instrucción compuesta detrás de la cláusula __try es el cuerpo o la sección protegida. La expresión __except también se conoce como la expresión de filtro. Su valor determina cómo se controla la excepción. La instrucción compuesta detrás de la cláusula __except es el controlador de excepción. El controlador especifica las acciones que se deben realizar si se produce una excepción durante la ejecución de la sección body. La ejecución continúa de la siguiente manera:

  1. Se ejecuta la sección protegida.

  2. Si no se produce ninguna excepción durante la ejecución de la sección protegida, continúa la ejecución de la instrucción después de la cláusula __except.

  3. Si se produce una excepción durante la ejecución de la sección protegida, o en cualquier rutina que llame la sección protegida, se evalúa la expresión __except. Hay tres valores posibles:

    • EXCEPTION_CONTINUE_EXECUTION (-1) Se descarta la excepción. La ejecución continúa en el punto donde se ha producido la excepción.

    • EXCEPTION_CONTINUE_SEARCH (0) No se reconoce la excepción. La búsqueda de un controlador continúa hacia la parte superior de la pila, primero con las instrucciones try-except contenedoras y, después, con los controladores siguientes que tengan mayor prioridad.

    • EXCEPTION_EXECUTE_HANDLER (1) La excepción se reconoce. Se transfiere el control al controlador de excepciones mediante la ejecución de la instrucción compuesta __except; después, la ejecución continúa tras el bloque __except.

La expresión __except se evalúa como una expresión de C. Está limitado a un solo valor, el operador de expresión condicional o el operador de coma. Si se requiere un mayor procesamiento, la expresión puede llamar a una rutina que devuelva uno de los tres valores enumerados anteriormente.

Cada aplicación puede tener su propio controlador de excepciones.

No es válido saltar dentro de una instrucción __try, pero sí fuera. El controlador de excepciones no se llama si un proceso finaliza en medio de la ejecución de una instrucción try-except.

Por compatibilidad con versiones anteriores, _try, _except y _leave son sinónimos de __try, __except y __leave a menos que se especifique la opción del compilador /Za (Deshabilitar extensiones de lenguaje).

La palabra clave __leave.

La palabra clave __leave solo es válida dentro de la sección protegida de una instrucción try-except y su efecto es saltar al final de la sección protegida. La ejecución de la primera instrucción continúa después del controlador de excepciones.

Una instrucción goto también puede saltar fuera de la sección protegida y no degrada el rendimiento como lo hace en una instrucción try-finally. Esto se debe a que no se produce el desenredo de la pila. Sin embargo, se recomienda usar la palabra clave __leave en lugar de una instrucción goto. El motivo es que es menos probable que comete un error de programación si la sección de protección es grande o compleja.

Funciones intrínsecas de control de excepciones estructurado

El manejo estructurado de excepciones proporciona dos funciones intrínsecas que están disponibles para usar con la instrucción try-except: GetExceptionCode y GetExceptionInformation.

GetExceptionCode devuelve el código (un entero de 32 bits) de la excepción.

La función intrínseca GetExceptionInformation devuelve un puntero a una estructura EXCEPTION_POINTERS que contiene información adicional sobre la excepción. A través de este puntero, se puede tener acceso al estado que tenía el equipo en el momento de producirse una excepción de hardware. La estructura es como sigue:

typedef struct _EXCEPTION_POINTERS {
    PEXCEPTION_RECORD ExceptionRecord;
    PCONTEXT ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;

Los tipos de puntero PEXCEPTION_RECORD y PCONTEXT se definen en el archivo de inclusión <winnt.h>, y _EXCEPTION_RECORD y _CONTEXT se definen en el archivo de inclusión <excpt.h>

Puede usar GetExceptionCode en el controlador de excepciones. Sin embargo, solo puede usar GetExceptionInformation dentro de la expresión de filtro de excepciones. La información a la que apunta suele estar en la pila y ya no está disponible cuando el control se transfiere al controlador de excepciones.

La función intrínseca AbnormalTermination está disponible dentro de un controlador de terminación. Devuelve 0 si el cuerpo de la instrucción try-finally finaliza secuencialmente. En todos los demás casos, devuelve 1.

<excpt.h> define algunos nombres alternativos para estos intrínsecos:

GetExceptionCode es equivalente a _exception_code

GetExceptionInformation es equivalente a _exception_info

AbnormalTermination es equivalente a _abnormal_termination

Ejemplo

// exceptions_try_except_Statement.cpp
// Example of try-except and try-finally statements
#include <stdio.h>
#include <windows.h> // for EXCEPTION_ACCESS_VIOLATION
#include <excpt.h>

int filter(unsigned int code, struct _EXCEPTION_POINTERS *ep)
{
    puts("in filter.");
    if (code == EXCEPTION_ACCESS_VIOLATION)
    {
        puts("caught AV as expected.");
        return EXCEPTION_EXECUTE_HANDLER;
    }
    else
    {
        puts("didn't catch AV, unexpected.");
        return EXCEPTION_CONTINUE_SEARCH;
    };
}

int main()
{
    int* p = 0x00000000;   // pointer to NULL
    puts("hello");
    __try
    {
        puts("in try");
        __try
        {
            puts("in try");
            *p = 13;    // causes an access violation exception;
        }
        __finally
        {
            puts("in finally. termination: ");
            puts(AbnormalTermination() ? "\tabnormal" : "\tnormal");
        }
    }
    __except(filter(GetExceptionCode(), GetExceptionInformation()))
    {
        puts("in except");
    }
    puts("world");
}

Salida

hello
in try
in try
in filter.
caught AV as expected.
in finally. termination:
        abnormal
in except
world

Consulte también

Escritura de un controlador de excepciones
Structured Exception Handling (C/C++)
Palabras clave