c error-handling longjmp setjmp

¿Cuáles son algunas maneras "buenas" de usar longjmp/setjmp para el manejo de errores en C?



error-handling (6)

Tengo que usar C para un proyecto y estoy pensando en usar longjmp/setjmp para el manejo de errores, ya que creo que será mucho más fácil manejar los errores en un lugar central que los códigos de retorno. Apreciaría si hay algunas pistas sobre cómo hacer esto.

Me preocupa especialmente que la limpieza de recursos se realice correctamente si se produce algún error de este tipo.

Además, ¿cómo manejo los errores que resultan en programas de subprocesos múltiples que los usan?

Aún mejor, ¿hay alguna biblioteca de C que ya existe para el manejo de errores / excepciones?



He usado setjmp / longjmp razonablemente ordenadamente, para escapar de una devolución de llamada, sin tener que negociar mi camino a través de otros niveles de biblioteca.

Ese caso (si recuerdo correctamente) fue cuando un código dentro de un analizador generado por yacc pudo detectar un problema (no sintáctico) y quiso abandonar el análisis pero devolver un informe de error razonablemente útil al llamante en el otro lado de Todo el código generado por yacc. Otro ejemplo fue dentro de una devolución de llamada llamada desde un analizador Expat. En cada caso, había otras formas de hacer esto, pero parecían más engorrosas y oscuras que simplemente escapar de esta manera.

Sin embargo, como han señalado otras respuestas, es necesario tener cuidado con la limpieza y ser muy cuidadosos al asegurarse de que el código longjmp solo sea llamable dentro del alcance de la región protegida dinámicamente por setjmp .

¿Haciéndolo en el contexto de la programación multi-hilo? Estoy seguro de que eso no es imposible, pero Oooh: saca tu paquete familiar de aspirinas ahora. Probablemente sea aconsejable mantener los pares setjmp / longjmp más cerca posible. Siempre y cuando un par setjmp / longjmp coincida esté dentro del mismo hilo, espero que estés bien, pero ... ten cuidado.


Las excepciones son, con mucho, un mejor mecanismo general, pero en los profundos días oscuros del pasado C, escribí un emulador de procesador que incluía un shell de comandos. El shell utilizado para establecer jmp / longjmp para el manejo de interrupciones (es decir, el procesador se está ejecutando y el usuario pulsa break / ctrl-c, el código atrapa SIGINT y longjmps de nuevo en el shell).


Si está preocupado por la limpieza de recursos, debe preguntarse seriamente si longjmp () y setjmp () son una buena idea.

Si diseña su sistema de asignación de recursos para que pueda limpiar de manera precisa, entonces está bien, pero ese diseño tiende a ser complicado y, por lo general, incompleto si, de hecho, las bibliotecas estándar que usa su código asignan recursos que deben ser liberado Requiere un cuidado extraordinario, y debido a que no es totalmente confiable, no es adecuado para sistemas de larga ejecución que pueden necesitar sobrevivir a múltiples usos de las llamadas a setjmp () / longjmp () (se filtrarán, expandirán y eventualmente causarán problemas).


Solo he encontrado un uso para setjmp()/longjmp() y no tenía nada que ver con el manejo de errores.

Realmente no hay necesidad de usarlo para eso, ya que siempre puede ser refaccionado en algo más fácil de seguir. El uso de setjmp()/longjmp() es muy similar a goto en que se puede abusar fácilmente. Cualquier cosa que haga que su código sea menos legible es una mala idea en general. Tenga en cuenta que no estoy diciendo que sean intrínsecamente malos, solo que pueden llevar a un código erróneo más fácil que las alternativas.

FWIW, el único lugar en el que tuvieron un valor incalculable fue un proyecto que hice en los primeros días de la industria (marco de tiempo de MS-DOS 6). Logré armar una biblioteca de subprocesos múltiples cooperativa utilizando Turbo C que usó esas funciones en una función de yield() para cambiar las tareas.

Estoy bastante seguro de que no los he tocado (o he tenido necesidad de hacerlo) desde esos días.


Symbian implementó el mecanismo Leave en términos de longjmp() y esto sirve como un buen recorrido de todas las cosas que necesita hacer.

Symbian tiene una ''pila de limpieza'' global que presionas y haces estallar las cosas que quieres que se limpien si ocurriera un salto. Esta es la alternativa manual al desenrollado automático de pila que hace un compilador de C ++ cuando se lanza una excepción de C ++.

Symbian tenía "arneses de trampa" a los que saltaría; estos podrían estar anidados

(Symbian más recientemente lo volvió a implementar en términos de excepciones de C ++, pero la interfaz permanece sin cambios).

Todos juntos, creo que las excepciones correctas de C ++ son menos propensas a errores de codificación y mucho más rápidas que tirar tu propio C equivalente.

(Por ejemplo, los compiladores modernos de C ++ son muy buenos para las excepciones de ''sobrecarga cero'' cuando no se lanzan; longjmp() tiene que almacenar el estado de todos los registros, incluso cuando el salto no se toma más tarde, por lo que, básicamente, nunca puede tan rápido como las excepciones.)

Usar C ++ como una mejor C, donde solo adoptas excepciones y RAII, sería una buena ruta si usar longjmp() para la emulación de excepciones sea tentador para ti.