C no admite el manejo de excepciones. Para lanzar una excepción en C, debe usar algo específico de la plataforma, como el manejo estructurado de excepciones de Win32, pero para brindar ayuda con eso, necesitaremos saber la plataforma que le interesa.
Jerry Coffin
18
... y no use el manejo estructurado de excepciones de Win32.
Brian R. Bondy
4
Usar setjmp () y longjmp () debería, en teoría, funcionar, pero no creo que valga la pena.
Sin embargo, las excepciones se definen en C ++ y otros lenguajes. El manejo de excepciones en C ++ se especifica en el estándar C ++ "Manejo de excepciones S.15", no hay una sección equivalente en el estándar C.
Entonces en C está garantizado que no habrá excepciones, ¿cómo?
httpinterpret
62
@httpinterpret: en C está "garantizado" que no hay excepciones de la misma forma que está "garantizado" que no hay plantillas, ni reflejos, ni unicornios. La especificación del lenguaje simplemente no define tal cosa. Sin embargo, existe setjmp / longjmp, que se puede usar para salir de una función sin regresar. Por lo tanto, los programas podrían crear sus propios mecanismos similares a excepciones si lo desearan, o una implementación en C podría definir extensiones al estándar.
Steve Jessop
2
Un programa maindentro de un .carchivo puede incluir algo de C ++ y, por lo tanto, las excepciones podrían ser lanzadas y atrapadas en el programa, pero las partes del código C permanecerán ignorantes de todo esto, excepto que el lanzamiento y la captura de excepciones a menudo se basan en funciones escritas en C que residen en las bibliotecas de C ++. C se usa porque no puede arriesgarse a que la función llamada a hacer tenga throwque lanzar una excepción. Sin embargo, puede haber una forma específica del compilador / biblioteca / objetivo para lanzar / capturar excepciones. Pero lanzar una instancia de clase tendrá sus propios problemas.
nategoose
61
@Steve: Por favor, avíseme si encuentra un idioma con unicornios, he estado esperando tal cosa durante años.
Brian R. Bondy
5
@ BrianR.Bondy Aquí hay un idioma con unicornios (lo garantizo de la misma manera que está garantizado en C)
Tofandel
37
En C, podría usar la combinación de las funciones setjmp()y longjmp(), definidas en setjmp.h. Ejemplo de Wikipedia
#include<stdio.h>#include<setjmp.h>static jmp_buf buf;void second(void){
printf("second\n");// prints
longjmp(buf,1);// jumps back to where setjmp // was called - making setjmp now return 1}void first(void){
second();
printf("first\n");// does not print}int main(){if(! setjmp(buf)){
first();// when executed, setjmp returns 0}else{// when longjmp jumps back, setjmp returns 1
printf("main");// prints}return0;}
Nota: De hecho, le aconsejaría que no los use, ya que funcionan mal con C ++ (no se llamaría a los destructores de objetos locales) y es muy difícil entender qué está pasando. En su lugar, devuelve algún tipo de error.
He visto que setjump / longjump no funciona correctamente en programas C ++ incluso cuando no hay objetos que necesiten ser destruidos cuando se usaron excepciones. Rara vez los uso en programas C.
nategoose
Este fue un enfoque interesante usando setjmp. on-time.com/ddj0011.htm Pero sí, básicamente tienes que inventarlos tú mismo si quieres la ejecución de código fuera de banda sin desenrollar la pila.
Dwayne Robinson
No estoy seguro de por qué la advertencia sobre su uso en C ++ cuando la pregunta es sobre C y C ++ tiene excepciones de todos modos. En cualquier caso, es importante que el OP sepa que para evitar que la implementación de setjmp / longjmp se dispare, siempre tenga en cuenta que primero debe visitar el controlador de errores (para configurarlo) y ese controlador de errores necesita regresar dos veces.
1
Por cierto, el manejo de excepciones era algo que realmente esperaba que hubiera terminado en C11. A pesar de la creencia común, no requiere OOP para funcionar correctamente, y C sufre interminablemente por cada llamada de función que requiere un if(). No veo peligro en eso; ¿Alguien más puede aquí?
@ user4229245 Tengo la impresión (anecdótica) de que cualquier cosa "hecha para usted" se mantiene fuera de la especificación del lenguaje c tanto como sea posible específicamente para mantener c relevante para la programación de máquinas y bare metal donde incluso los fundamentos del status quo como bytes de ocho bits no están no es universal, solo mis pensamientos, aunque no soy un autor de especificaciones
ThorSummoner
21
El viejo C simple no admite excepciones de forma nativa.
Puede utilizar estrategias alternativas de manejo de errores, como:
devolviendo un código de error
regresar FALSEy usar una last_errorvariable o función.
Además, la API de Windows tiene el mismo método para manejar los errores. por ejemplo GetLastError()en la API de Windows.
BattleTested el
20
No hay ningún mecanismo de excepción incorporado en C; necesita simular excepciones y su semántica. Por lo general, esto se logra confiando en setjmpy longjmp.
Hay bastantes bibliotecas y estoy implementando otra más. Se llama exceptions4c ; es portátil y gratuito. Puede echarle un vistazo y compararlo con otras alternativas para ver cuál le queda más.
Leí su ejemplo de código, comencé un proyecto similar con una estructura, pero usa un uuid en lugar de una cadena para identificar cada "excepción". Tu proyecto parece muy prometedor.
¿Conoce usted (o alguien más) acerca de una comparación entre los diferentes paquetes de excepción?
Marcel Waldvogel
11
C es capaz de lanzar una excepción de C ++, de todos modos son códigos de máquina. Por ejemplo, en bar.c
// begin bar.c#include<stdlib.h>#include<stdint.h>externvoid*__cxa_allocate_exception(size_t thrown_size);externvoid __cxa_throw (void*thrown_exception,void**tinfo,void(*dest)(void*));externvoid*_ZTIl;// typeinfo of longint bar1(){int64_t* p =(int64_t*)__cxa_allocate_exception(8);*p =1976;
__cxa_throw(p,&_ZTIl,0);return10;}// end bar.c
¿Qué diablos es "_ZTIl" ??? No puedo encontrar ninguna referencia a él en ninguna parte y es un completo misterio cómo haría posible que el código C tuviera acceso a std :: type_info. ¡Por favor, ayúdame!
AreusAstarte
1
_ZTIIsignifica typeinfo for long, por ejemplo echo '_ZTIl' | c++filt . Es el esquema de manipulación de g ++.
wcy
y solo por si acaso, asegúrese de llamar al símbolo ac en el bloque de captura para evitar c ++ tanto como sea posible: P (PD, ¡gracias por compartir un excelente ejemplo real!)
ThorSummoner
8
Esta pregunta es muy antigua, pero me encontré con ella y pensé en compartir una técnica: dividir por cero o eliminar la referencia a un puntero nulo.
La pregunta es simplemente "cómo lanzar", no cómo atrapar, o incluso cómo lanzar un tipo específico de excepción. Tuve una situación hace mucho tiempo en la que necesitábamos activar una excepción de C para quedar atrapados en C ++. Específicamente, teníamos informes ocasionales de errores de "llamada de función virtual pura" y necesitábamos convencer a la función _purecall del tiempo de ejecución de C para que arrojara algo. Así que agregamos nuestra propia función _purecall que dividida por cero, y boom, obtuvimos una excepción que pudimos detectar en C ++, e incluso usar un poco de diversión de pila para ver dónde salieron las cosas.
Como se menciona en numerosos hilos, la forma "estándar" de hacer esto es usando setjmp / longjmp. Publiqué otra solución de este tipo en https://github.com/psevon/exceptions-and-raii-in-c. Según
mi conocimiento, esta es la única solución que se basa en la limpieza automática de los recursos asignados. Implementa punteros inteligentes únicos y compartidos, y permite que las funciones intermedias permitan que las excepciones pasen sin detectarse y aún así tener sus recursos asignados localmente limpiados correctamente.
C no admite excepciones. Puede intentar compilar su código C como C ++ con Visual Studio o G ++ y ver si se compila como está. La mayoría de las aplicaciones C se compilarán como C ++ sin cambios importantes, y luego puede usar la sintaxis try ... catch.
Si escribe código con el patrón de diseño Happy path (es decir, para el dispositivo integrado), puede simular el procesamiento de errores de excepción (también conocido como diferir o finalmente emular) con el operador "goto".
int process(int port){int rc;int fd1;int fd2;
fd1 = open("/dev/...",...);if(fd1 ==-1){
rc =-1;goto out;}
fd2 = open("/dev/...",...);if(fd2 ==-1){
rc =-1;goto out;}// Do some with fd1 and fd2 for example write(f2, read(fd1))
rc =0;
out://if (rc != 0) {(void)close(fd1);(void)close(fd2);//}return rc;}
En realidad, no es un controlador de excepciones, pero le brinda una manera de manejar el error en la salida de la función.
PD: debe tener cuidado de usar goto solo desde el mismo ámbito o más profundo y nunca saltar la declaración de variable.
Respuestas:
No hay excepciones en C. En C, los errores se notifican mediante el valor devuelto de la función, el valor de salida del proceso, las señales al proceso ( señales de error del programa (GNU libc) ) o la interrupción del hardware de la CPU (u otra notificación error de la CPU si lo hay) ( Cómo el procesador maneja el caso de división por cero ).
Sin embargo, las excepciones se definen en C ++ y otros lenguajes. El manejo de excepciones en C ++ se especifica en el estándar C ++ "Manejo de excepciones S.15", no hay una sección equivalente en el estándar C.
fuente
main
dentro de un.c
archivo puede incluir algo de C ++ y, por lo tanto, las excepciones podrían ser lanzadas y atrapadas en el programa, pero las partes del código C permanecerán ignorantes de todo esto, excepto que el lanzamiento y la captura de excepciones a menudo se basan en funciones escritas en C que residen en las bibliotecas de C ++. C se usa porque no puede arriesgarse a que la función llamada a hacer tengathrow
que lanzar una excepción. Sin embargo, puede haber una forma específica del compilador / biblioteca / objetivo para lanzar / capturar excepciones. Pero lanzar una instancia de clase tendrá sus propios problemas.En C, podría usar la combinación de las funciones
setjmp()
ylongjmp()
, definidas ensetjmp.h
. Ejemplo de WikipediaNota: De hecho, le aconsejaría que no los use, ya que funcionan mal con C ++ (no se llamaría a los destructores de objetos locales) y es muy difícil entender qué está pasando. En su lugar, devuelve algún tipo de error.
fuente
if()
. No veo peligro en eso; ¿Alguien más puede aquí?El viejo C simple no admite excepciones de forma nativa.
Puede utilizar estrategias alternativas de manejo de errores, como:
FALSE
y usar unalast_error
variable o función.Consulte http://en.wikibooks.org/wiki/C_Programming/Error_handling .
fuente
GetLastError()
en la API de Windows.No hay ningún mecanismo de excepción incorporado en C; necesita simular excepciones y su semántica. Por lo general, esto se logra confiando en
setjmp
ylongjmp
.Hay bastantes bibliotecas y estoy implementando otra más. Se llama exceptions4c ; es portátil y gratuito. Puede echarle un vistazo y compararlo con otras alternativas para ver cuál le queda más.
fuente
C es capaz de lanzar una excepción de C ++, de todos modos son códigos de máquina. Por ejemplo, en bar.c
en a.cc,
para compilarlo
salida
http://mentorembedded.github.io/cxx-abi/abi-eh.html tiene más información detallada sobre
__cxa_throw
.No estoy seguro de si es portátil o no, y lo pruebo con 'gcc-4.8.2' en Linux.
fuente
_ZTII
significatypeinfo for long
, por ejemploecho '_ZTIl' | c++filt
. Es el esquema de manipulación de g ++.Esta pregunta es muy antigua, pero me encontré con ella y pensé en compartir una técnica: dividir por cero o eliminar la referencia a un puntero nulo.
La pregunta es simplemente "cómo lanzar", no cómo atrapar, o incluso cómo lanzar un tipo específico de excepción. Tuve una situación hace mucho tiempo en la que necesitábamos activar una excepción de C para quedar atrapados en C ++. Específicamente, teníamos informes ocasionales de errores de "llamada de función virtual pura" y necesitábamos convencer a la función _purecall del tiempo de ejecución de C para que arrojara algo. Así que agregamos nuestra propia función _purecall que dividida por cero, y boom, obtuvimos una excepción que pudimos detectar en C ++, e incluso usar un poco de diversión de pila para ver dónde salieron las cosas.
fuente
int div_by_nil(int x) { return x/0; }
En Win con MSVC hay,
__try ... __except ...
pero es realmente horrible y no querrás usarlo si puedes evitarlo. Mejor decir que no hay excepciones.fuente
C no tiene excepciones.
Hay varias implementaciones de hacky que intentan hacerlo (un ejemplo en: http://adomas.org/excc/ ).
fuente
Como se menciona en numerosos hilos, la forma "estándar" de hacer esto es usando setjmp / longjmp. Publiqué otra solución de este tipo en https://github.com/psevon/exceptions-and-raii-in-c. Según mi conocimiento, esta es la única solución que se basa en la limpieza automática de los recursos asignados. Implementa punteros inteligentes únicos y compartidos, y permite que las funciones intermedias permitan que las excepciones pasen sin detectarse y aún así tener sus recursos asignados localmente limpiados correctamente.
fuente
C no admite excepciones. Puede intentar compilar su código C como C ++ con Visual Studio o G ++ y ver si se compila como está. La mayoría de las aplicaciones C se compilarán como C ++ sin cambios importantes, y luego puede usar la sintaxis try ... catch.
fuente
Si escribe código con el patrón de diseño Happy path (es decir, para el dispositivo integrado), puede simular el procesamiento de errores de excepción (también conocido como diferir o finalmente emular) con el operador "goto".
En realidad, no es un controlador de excepciones, pero le brinda una manera de manejar el error en la salida de la función.
PD: debe tener cuidado de usar goto solo desde el mismo ámbito o más profundo y nunca saltar la declaración de variable.
fuente