ProgramaciónDesarrollador C

¿Cómo se implementa el manejo de errores en el lenguaje C? ¿Cuáles son las diferencias entre setjmp/longjmp, errno y el retorno de código de error? ¿Cuándo se debe usar cada enfoque?

Supere entrevistas con el asistente de IA Hintsage

Respuesta

En el lenguaje C no hay soporte incorporado para excepciones, el manejo de errores se implementa de las siguientes maneras:

  1. Retorno de código de error (generalmente a través del valor de la función) Ejemplo:

    int read_file(const char *name) { FILE *f = fopen(name, "r"); if (!f) return -1; // Error // ... fclose(f); return 0; // Éxito }
  2. Uso de la variable global errno Al ocurrir un error, las funciones estándar a menudo establecen la variable global errno. Ejemplo:

    FILE *fp = fopen("nofile", "r"); if (!fp) { perror("Error de archivo"); // errno determina la causa }
  3. setjmp/longjmp — mecanismo para lanzar una "excepción" (el contexto de ejecución se guarda y se restablece) Se utiliza para casos complejos (por ejemplo, finalización de emergencia entre niveles). Se usa raramente, ya que complica el código y puede causar fugas de recursos.

    #include <setjmp.h> jmp_buf buf; if (setjmp(buf) == 0) { // ... longjmp(buf, 1); // Regresa a if (setjmp(...)) } else { // Manejo de errores }
  • Retorno de código de error — el método principal, simple y seguro.
  • errno — conveniente para funciones de biblioteca.
  • setjmp/longjmp — para casos específicos (bibliotecas complejas o intérpretes).

Pregunta capciosa

¿Qué imprimirá el siguiente código?

#include <stdio.h> #include <setjmp.h> jmp_buf buf; void func() { longjmp(buf, 5); } int main() { int val = setjmp(buf); printf("val=%d\n", val); if (val == 0) func(); return 0; }

Respuesta:

  • En la primera llamada, setjmp devuelve 0 y se llama a la función func.
  • En ella se produce longjmp(buf, 5), la ejecución vuelve a setjmp, que ahora devuelve 5.
  • La salida final:
    val=0
    val=5
    

Ejemplos de errores reales debido a la falta de conocimiento sobre los matices del tema


Historia En una biblioteca se implementó un mecanismo manual de limpieza de recursos al error solo por código de retorno. Pero el programador olvidó manejar el error al retornar no desde el hilo principal, sino desde un callback (a través de setjmp/longjmp), resultando en fugas de memoria y bloqueos de archivos.


Historia En una aplicación de red se omitió la verificación de errno después de la operación de socket. Debido a esto, surgió un diagnóstico falso: la variable errno conservó un viejo valor incorrecto de la función anterior.


Historia El equipo implementó una compleja anidación con múltiples puntos de retorno de código de error, pero no siguieron la convención sobre los valores de retorno (cero/valores negativos). Algunos errores se interpretaron como exitosos, lo que llevó a fallos inesperados del servicio.