Escribí esto en Google pero solo encontré howtos en C ++,
¿cómo hacerlo en C?
Escribí esto en Google pero solo encontré howtos en C ++,
¿cómo hacerlo en C?
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.
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 tenga throw
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()
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
}
return 0;
}
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.
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 una last_error
variable o función.Consulte http://en.wikibooks.org/wiki/C_Programming/Error_handling .
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
y 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.
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>
extern void *__cxa_allocate_exception(size_t thrown_size);
extern void __cxa_throw (void *thrown_exception, void* *tinfo, void (*dest) (void *) );
extern void * _ZTIl; // typeinfo of long
int bar1()
{
int64_t * p = (int64_t*)__cxa_allocate_exception(8);
*p = 1976;
__cxa_throw(p,&_ZTIl,0);
return 10;
}
// end bar.c
en a.cc,
#include <stdint.h>
#include <cstdio>
extern "C" int bar1();
void foo()
{
try{
bar1();
}catch(int64_t x){
printf("good %ld",x);
}
}
int main(int argc, char *argv[])
{
foo();
return 0;
}
para compilarlo
gcc -o bar.o -c bar.c && g++ a.cc bar.o && ./a.out
salida
good 1976
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.
_ZTII
significa typeinfo for long
, por ejemplo echo '_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.
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.
C no tiene excepciones.
Hay varias implementaciones de hacky que intentan hacerlo (un ejemplo en: http://adomas.org/excc/ ).
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.