[C con Clase] Macro para gestionar errores

Steven Davidson srd4121 en njit.edu
Mie Mar 4 18:44:55 CET 2009


Hola Vicente,

vicente lozano wrote:
> Ok, gracias por contestar.
> 
> El porque define es porque vengo de C y aun no habia llegado a las 
> constantes jeje.
> 
> perror y sterror no las conocia aun, pero aun asi es para gestionar
> mis propios errores en las funciones.
> 
> Por otro lado, para que los mensajes de error puedan ser en
> diferentes idiomas existe algo o hay que hacerlo asi?
> 

Hay varias formas de hacer esto. Puedes usar directivas del 
precompilador para modificar tu código fuente. Por ejemplo,

// errores.h

#ifdef ERRORES_ENG
const char *ERRORS[] = { "Opening file", "Writing file",
                          "Creating Socket",...};
#else
#ifdef ERRORES_ESP
const char *ERRORS[] = { "Abriendo fichero", "Escribiendo fichero",
                          "Creando Socket",...};
#else
#ifdef ERRORES_FRA
const char *ERRORS[] = { "Ouvrant fichier", "Fermant fichier",
                          "Créant Socket",...};
#else
...
#else  // Por defecto, español
#define ERRORES_ESP
const char *ERRORS[] = { "Abriendo fichero", "Escribiendo fichero",
                          "Creando Socket",...};
#endif

En tu código fuente, #define la constante simbólica que te interese. Por 
ejemplo,

// main.cpp

// Elegimos inglés para los mensajes de errores
#define ERRORES_ENG
#include "errores.h"
...

Claro está, no puedes cambiar el idioma una vez compilado tu programa. 
Si quieres mayor control, entonces usa punteros. Por ejemplo,

// main.cpp

const char *ERRORS_ENG[] = { "Opening file", "Writing file",
                              "Creating Socket",...};
const char *ERRORS_ESP[] = { "Abriendo fichero", "Escribiendo fichero",
                              "Creando Socket",...};
const char *ERRORS_FRA[] = { "Ouvrant fichier", "Fermant fichier",
                              "Créant Socket",...};
...

// Español, por defecto
const char **ERRORS = ERRORS_ESP;

El resto del código fuente usa el puntero 'ERRORS'. Si quieres cambiar 
el idioma, simplemente, cambia el valor de 'ERRORS' para "apuntar" a 
otro array de cadenas de caracteres. Por ejemplo,

if( <francés> )  ERRORS = ERRORS_FRA;

Todo lo demás sigue igual.

Otra solución es parecida a esta última, pero en lugar de escribir la 
información en el propio código fuente, lo hacemos en un fichero de 
texto. Luego, nuestro programa carga esta información en el array de 
cadenas según la configuración que tenemos. Por ejemplo,

bool CargarMensajes( const char *szErrores[], const char szFichero[] );
...
char ERRORS[10][128]={0};
// Cargar mensajes en español
CargarMensajes( ERRORS, "errores_esp.txt" );
...
if( <francés> )  CargarMensajes( ERRORS, "errores_fra.txt" );

La función 'CargarMensajes()' se encargará de leer las cadenas del 
fichero indicado - si puede - y copiarlas al array de cadenas dado.

> Gracias y perdonar por mi desconocimiento de las librerias, me pasa 
> mucho lo de pensar algo, ponerme a hacerlo y luego descubrir que
> existe alguna funcion de libreria que podia haber usado. Espero que
> el capitulo de librerias me ayude a solucionar ese "problemilla"
> 

Bueno, al menos así aprendes todos los detalles de cualesquier temas. A 
veces viene bien hacer las cosas uno mismo, pero otras veces no.


Como ha dicho Ferrán, es mejor usar funciones en línea agregando el 
vocablo 'inline' como prefijo a la declaración o definición de la 
función. Si quieres usar una macro, aconsejo reescribirlo de esta manera:

#define check(cond,errn)\
   ( -1==cond ? fprintf(stderr, "ERROR: %s.\n", ERRORS[errn]) : -1 )

Ten mucho cuidado con macros y sus #definiciones. Las macros no son 
funciones. Pensar así es la causa de errores y de muchos quebraderos de 
cabeza. Por esta razón, en C++ usamos funciones 'inline' por la 
oportunidad de optimizar la función como una macro.


Espero haber aclarado las dudas.

Steven





Más información sobre la lista de distribución Cconclase