2011-01-31 8 views
8

De acuerdo con los documentos, fprintf puede fallar y devolverá un número negativo si falla. Claramente, hay muchas situaciones en las que sería útil verificar este valor.Error al verificar fprintf al imprimir en stderr

Sin embargo, suelo usar fprintf para imprimir mensajes de error en stderr. Mi código suele ser algo como esto:

rc = foo(); 
if(rc) { 
    fprintf(stderr, "An error occured\n"); 
    //Sometimes stuff will need to be cleaned up here 
    return 1; 
} 

En estos casos, es todavía posible que fprintf falle? Si es así, ¿hay algo que se pueda hacer para mostrar el mensaje de error de alguna manera o existe una alternativa más confiable a fprintf?

Si no es así, ¿hay alguna necesidad de comprobar fprintf cuando se utiliza de esta manera?

Respuesta

12

El estándar C dice que las secuencias de archivos stdin, stdout y stderr se conectarán en algún lugar, pero no especifican dónde, por supuesto. Es perfectamente factible ejecutar un programa con ellos redirigida:

some_program_of_yours >/dev/null 2>&1 </dev/null 

Sus escrituras tendrán éxito - pero la información no va a ninguna parte. Una forma más brutal de funcionamiento de su programa es:

some_program_of_yours >&- 2>&- </dev/null 

En esta ocasión, ha sido ejecutado sin flujos de archivos abiertos para stdout y stderr - en contravención de la la norma. Sigue leyendo desde/dev/null en el ejemplo, lo que significa que no recibe ninguna entrada de datos útil de stdin.

Muchos programas no se molestan en verificar que los canales de E/S estándar estén abiertos. Muchos programas no se molestan en verificar que el mensaje de error haya sido escrito correctamente. Diseñar un repliegue adecuado como esquema por Tim Post y whitey04 no siempre vale la pena el esfuerzo. Si ejecuta el comando ls con sus salidas suprimidos, simplemente hacer lo que se pueda y salidas con un estado distinto de cero:

$ ls; echo $? 
gls 
0 
$ ls >&- 2>&-; echo $? 
2 
$ 

(Probado RHEL Linux.) Realmente no hay una necesidad de que ésta hacer más. Por otro lado, si se supone que su programa se ejecuta en segundo plano y escribe en un archivo de registro, probablemente no escriba mucho a stderr, a menos que no abra el archivo de registro (o vea un error en el archivo de registro) .

Tenga en cuenta que si recurre a syslog(3) (o POSIX), no tiene manera de saber si sus llamadas fueron "exitosas" o no; las funciones syslog no devuelven ninguna información de estado. Solo debes asumir que tuvieron éxito. Es su último recurso, por lo tanto.

+0

Me pregunto por qué esto no ha recibido más votos que mi respuesta. +1. –

+0

@Tim: gracias, pero su respuesta también proporciona buena información, y llegó primero. Y su punto clave, usar una función que reporte los errores, no un párrafo de código cada vez que necesite informar un error, es muy importante. –

4

Puede poner el error en stdout o en otro lugar ... En algún momento solo tiene que dar un error informando un mejor esfuerzo y luego darse por vencido.

La clave es que su aplicación "con gracia" lo maneja (por ejemplo, el sistema operativo no tiene que matarlo por ser malo y le dice por qué salió [si puede]).

9

Normalmente, emplearía algún tipo de sistema de registro que podría (trataría) de manejar esto por usted, o tendrá que duplicar esa lógica en cada área de su código que se imprime a error estándar y se cierra.

usted tiene algunas opciones:

  • Si fprintf falla, intenta syslog.
  • Si ambos fallan, intente crear un archivo 'crash. {Pid} .log' que contenga la información que desea en un informe de error. Verifique la existencia de estos archivos cuando inicie, ya que pueden decirle a su programa que se bloqueó anteriormente.
  • Deje que los usuarios conectados a la red verifiquen una opción de configuración que permita que su programa envíe un informe de errores.

Por cierto, open()read() y write() son buenos amigos para tener cuando la familia de funciones fprintf no están funcionando.

Como whitey04 says, a veces solo tiene que darse por vencido y hacer todo lo posible para no derretirse con los fuegos artificiales que se apagan. Pero trate de aislar ese tipo de lógica en una pequeña biblioteca.

Por ejemplo:

best_effort_logger(LOG_CRIT, "Heap corruption likely, bailing out!"); 

es mucho más limpio que una serie de ifelseelse if cada lugar cosas podría salir mal.

2

Algunos programas que realmente desea registrar mensajes de error establecerá un pila alternativa al inicio del programa hasta reservar cierta cantidad de memoria (ver sigaltstack(2) que puede ser utilizado por un controlador de señal (por lo general SIGSEGV) a informe errores. Dependiendo de la importancia de registrar su error, podría investigar el uso de pilas alternativas para preasignar parte de la memoria. Puede que no valga la pena :) pero a veces daría cualquier cosa por pista de lo que sucedió .

3

Sí, por supuesto fprintf a stderr puede fallar. Por ejemplo, stderr podría ser un archivo ordinario y el disco podría quedarse sin espacio, o podría ser un conducto que se cierra por el lector, etc.

Si se comprueba si una operación falla, depende en gran medida de si se puede lograr un mejor comportamiento del programa al verificar. En su caso, las únicas cosas imaginables que podría hacer al no imprimir el mensaje de error son intentar imprimir otro (que seguramente también fallará) o salir del programa (lo que es probablemente peor que no informar un error, pero quizás no siempre).

Cuestiones relacionadas