2010-03-09 9 views
11

A veces tengo que escribir un código que alterna entre hacer cosas y verificar condiciones de error (por ejemplo, llamar a una función de biblioteca, verificar su valor de retorno, continuar). Esto a menudo conduce a recorridos largos, donde el trabajo real que está sucediendo en las condiciones de las sentencias if, comobuen estilo c al verificar muchos valores devueltos

if(! (data = (big_struct *) malloc(sizeof(*data)))){ 
    //report allocation error 
} else if(init_big_struct(data)){ 
    //handle initialization error 
} else ... 

¿Cómo ustedes escriben este tipo de código? He revisado algunas guías de estilo, pero parecen más preocupadas por la nomenclatura variable y el espacio en blanco.

Enlaces a guías de estilo de bienvenida.

Editar: en caso de que no esté claro, estoy insatisfecho con la legibilidad de este estilo y estoy buscando algo mejor.

+1

Mientras tanto, yo personalmente abandonaría el reparto '(big_struct *)' a menos que se requiera que use un compilador de C++ para compilar este código. Es un tema polémico, pero si no tienes ningún requisito de C++, creo que es mejor dejarlo. –

Respuesta

15

Aunque me duele decirlo, este podría ser un caso para el nunca popular goto. Aquí hay un enlace que encontré sobre el tema: http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c/

+0

Si no está de acuerdo con ver 'goto' en su código, siempre puede ocultarlo. http://stackoverflow.com/questions/2314066/do-whilefalse – jschmier

+1

+1 El uso de goto sigue siendo la mejor manera en este lenguaje horrible. – Tronic

+1

sí - esta es una buena práctica para el código C (en excepciones de uso de código de C++ y RAII). establecer recursos ptrs a NULL; establecer luego cuando se obtuvo y tener un punto de salida común que libera si! NULL. El único inconveniente es que realmente te hace poner todas tus variables de recursos en el máximo alcance de la función (prefiero declarar lo más localmente posible) – pm100

13

suelo escribir ese código de esta manera:

data = (big_struct *) malloc(sizeof(*data)); 
if(!data){ 
    //report allocation error 
    return ...; 
} 

err = init_big_struct(data); 
if(err){ 
    //handle initialization error 
    return ...; 
} 

... 

De esta manera evito llamar a funciones dentro de si, y la depuración es más fácil porque se puede comprobar los valores de retorno.

3

No use assert en el código de producción.
En el modo de depuración, assert nunca debe ser usado para algo que realmente puede suceder (como malloc regresar NULL), sino que se debe utilizar en casos imposibles (como índice de la matriz está fuera de límites en C)

Read this post for more.

2

Un método que utilicé con gran efecto es el utilizado por W. Richard Stevens en Unix Network Programming. El código se puede descargar here. Para las funciones comunes que espera tener éxito todo el tiempo, y no tiene ningún recurso para una falla, las envuelve , usando una letra mayúscula (código comprimido verticalmente):

void * Malloc(size_t size) { 
    void *ptr; 
    if ((ptr = malloc(size)) == NULL) 
     err_sys("malloc error"); 
    return(ptr); 
} 

err_sys aquí muestra el error y luego realiza un exit(1). De esta forma, puede llamar a Malloc y saber que se producirá un error si hay un problema.

UNP sigue siendo el único libro que tengo donde creo que el autor tiene un código que comprueba los valores de devolución de todas las funciones que es posible fallar. Cada otro libro dice "deberías verificar los valores devueltos, pero lo dejaremos para que lo hagas más tarde".

+2

Cabe señalar que, aunque esa solución suele ser buena para un programa independiente, es una muy mala idea para manejar los errores de esta manera en las bibliotecas, nunca deben abortar inesperadamente. –

0

I tienden a

  • comprobación de errores Delegado al envoltorio funciones (como Stevens)
  • En caso de error, simular excepciones usando longjmp. (Que de hecho uso de Dave Hanson C Interfaces and Implementations para simular excepciones.)

Otra opción es utilizar de literate programming Don Knuth para gestionar el código de control de errores, o algún otro tipo de preprocesador.Esta opción solo está disponible si establece las reglas para su tienda :-)

0

La única propiedad de agrupación de código como este es que simplemente hay una secuencia impuesta externamente que debe seguir. Es por eso que pone estas asignaciones en una función, pero esta es una característica común muy débil. El por qué algunas personas recomiendan abandonar las ventajas de alcance de los if anidados es incomprensible. De hecho, estás tratando de poner lápiz labial en un cerdo (no se pretende insultar): la naturaleza del código nunca arrojará nada limpio, lo mejor que puedes hacer es usar la ayuda del compilador para detectar errores (de mantenimiento). Quédese con el if en mi humilde opinión.

PD: si aún no te he convencido: ¿cómo será la solución goto si tomas decisiones ternarias? El if se pondrá más feo seguramente, pero el goto es ???

Cuestiones relacionadas