fclose
requiere como argumento un FILE
puntero obtenido por fopen
, uno de los flujos estándar stdin
, stdout
o stderr
, o de alguna otra forma definida por la implementación. Un puntero nulo no es uno de estos, por lo que el comportamiento no está definido, al igual que fclose((FILE *)0xdeadbeef)
sería. NULL no es especial Cía; Aparte del hecho de que está garantizado para comparar no es igual a cualquier puntero válido, es como cualquier otro puntero no válido, y usarlo invoca un comportamiento indefinido excepto cuando la interfaz lo está pasando a los documentos como parte de su contrato que NULL
tiene un significado especial.
Además, regresar con un error sería válido (ya que el comportamiento no está definido de todos modos) pero sería un comportamiento dañino para una implementación, porque oculta el comportamiento indefinido . El resultado preferible de invocar un comportamiento indefinido es siempre un bloqueo, porque resalta el error y le permite corregirlo. La mayoría de los usuarios de fclose
no verifique si hay un valor de retorno de error, y apuesto a que la mayoría de las personas son lo suficientemente tontas como para pasar NULL
a fclose
no van a ser lo suficientemente inteligentes como para comprobar el valor de retorno de fclose
. Se podría argumentar que las personas deberían verifique el valor de retorno de fclose
en general, ya que el vaciado final podría fallar, pero esto no es necesario para archivos que se abren solo para lectura, o si fflush
fue llamado manualmente antes de fclose
(que es un idioma más inteligente de todos modos porque es más fácil manejar el error mientras aún tiene el archivo abierto).
fclose(NULL)
debería triunfar. free(NULL)
tiene éxito, porque eso hace que sea más fácil escribir código de limpieza.
Lamentablemente, no es así como se definió. Por lo tanto, no puede usar fclose(NULL)
en programas portátiles. (Por ejemplo, consulte http://pubs.opengroup.org/onlinepubs/9699919799/).
Como han mencionado otros, generalmente no desea que se devuelva un error si pasa NULL al lugar equivocado. Desea un mensaje de advertencia, al menos en las compilaciones de depuración/prueba. Eliminar la referencia a NULL le brinda un mensaje de advertencia inmediato y la oportunidad de recopilar un seguimiento que identifica el error de programación :). Mientras está programando, una falla de segmento es el mejor error que puede obtener. C tiene muchos errores más sutiles, que tardan mucho más en depurarse...
Es posible abusar de las devoluciones de error para aumentar la robustez frente a errores de programación. Sin embargo, si le preocupa que un bloqueo del software pueda perder datos, tenga en cuenta que puede ocurrir exactamente lo mismo, p. si su hardware pierde energía. Es por eso que tenemos guardado automático (desde los editores de texto de Unix con nombres de dos letras como ex y vi). Aún sería preferible que su software se bloquee visiblemente, en lugar de continuar con un estado inconsistente.
Los errores de los que habla la página del manual son errores de tiempo de ejecución, no errores de programación. No puedes simplemente pasar NULL
en cualquier API que espera un puntero y espera que esa API haga algo razonable. Pasar un NULL
puntero a una función documentada para requerir un puntero a datos es un error.
Pregunta relacionada:En C o C++, ¿debo verificar los parámetros del puntero con NULL/nullptr?
Para citar el comentario de R. sobre una de las respuestas a esa pregunta:
... parece estar confundiendo errores que surgen de condiciones excepcionales en el entorno operativo (fs full, out of memory, network down, etc.) con errores de programación. En el primer caso, por supuesto, un programa robusto necesita poder manejarlos con gracia. En este último, un programa robusto no puede experimentarlos en primer lugar.