2010-09-01 9 views
12

En una prueba, estoy descartando cualquier cosa de stderr ya que desorienta la salida del caso de prueba. Estoy usando el siguiente código:Casting to void no elimina el error warn_unused_result

freopen("/dev/null", "w", stderr); 

Al compilar con -Wall -Werror, me sale el error

error: ignoring return value of ‘freopen’, declared with attribute warn_unused_result 

que se espera. Sin embargo, la solución habitual de fundición a void no parece funcionar. Es decir, cambiar el código a

(void) freopen("/dev/null", "w", stderr); 

sigue produciendo la misma advertencia. No me importa si esta función falla, ya que el peor escenario es un poco de producción adicional. ¿De otra manera puedo arreglar esto?

EDIT: Sé que podría introducir una variable adicional innecesaria. Realmente me gustaría saber por qué no funciona el lanzamiento al vacío.

ACTUALIZACIÓN: yo decidimos ir con esto:

FILE *null = fopen("/dev/null", "w"); 
if (null) { fclose(stderr); stderr = null; } 

Después de leer la documentación freopen con más cuidado, veo que si la apertura /dev/null falla, stderr todavía será destruida. Esto resuelve ese problema.

+4

'nulo' es un mal nombre para una variable C . –

+0

Buen punto. No sé lo que pensé que era una buena idea. –

Respuesta

6

Por qué no simplemente use el resultado, como advertencia lo que debes hacer

if (freopen("/dev/null", "w", stderr) == 0) 
    ...oops...lost stderr...hard to report errors... 

Dado que la función se declara con el atributo '' warn_unused_result, recibirá el aviso a menos que utilice el valor de retorno. Como la función devuelve null en caso de error o el argumento de flujo de archivo en caso de éxito, puede pensar en asignar el resultado. Sin embargo, no se debe asignar a stderr así (véase más adelante), por lo que esta es una mala idea:

stderr = freopen("/dev/null", "w", stderr); 

En teoría, usted debe hacer el registro de entrada; existen circunstancias graves (y poco plausibles) en las que no se puede abrir "/ dev/null".


nota al pie 229 en los C99 notas estándar:

229) El principal uso de la función freopen es cambiar el fichero asociado con un flujo de texto estándar (stderr, stdin, o stdout), ya que esos identificadores no necesitan ser valores modificables l a los que se les puede asignar el valor devuelto por la función fopen.

Por lo tanto, la asignación es desacertada. Pero probar el valor de retorno se ocuparía de la advertencia del compilador y también podría ayudar a prevenir los volcados del núcleo. Sin embargo, es poco probable que mejore sus cifras de cobertura de código (la ruta de error no se tomará con mucha frecuencia, será difícil forzar la cobertura del manejo de errores).

Tenga en cuenta que la descripción POSIX de freopen() tiene algunos comentarios moderadamente cáusticos sobre el diseño de freopen(), que fue inventado por el comité de C estándar (1989 versión), presumiblemente sin la participación de POSIX.

+0

Gracias. Haces un buen punto. –

2
int tossmeout = freopen("/dev/null", "w", stderr); 

Como comenta a continuación tratan

FILE *tossmeout = freopen("/dev/null", "w", stderr); 

y

(void *)freopen("/dev/null", "w", stderr); 
+1

Claro. ¿Pero hay una manera de hacer esto sin crear una variable innecesaria? –

+0

Además, 'freopen' devuelve' FILE * '. – dreamlax

+0

@Michael: la mayoría de los compiladores no "crearán" una variable; simplemente la colocan en una tabla de símbolos y solo reservan espacio para ella si se hace referencia a ella. - ellos * podrían * ser perezosos incrementar el puntero de la pila para el almacenamiento local. – Hogan

11

un poco pesado en las extensiones del CCG, pero las variables no visibles externamente:

#define ignore_result(x) ({ typeof(x) z = x; (void)sizeof z; }) 
ignore_result(freopen("/dev/null", "w", stderr)); 
+0

Sugeriría usar __typeof __() en lugar de typeof(). –

2

Si realmente tiene que utilizar el lenguaje C (no C++) entonces puede usar esta solución:

inline void ignore_result_helper(int __attribute__((unused)) dummy, ...) 
{ 
} 

#define IGNORE_RESULT(X) ignore_result_helper(0, (X)) 

Por ejemplo

typedef struct A 
{ 
    int x; 
} A; 

__attribute__((warn_unused_result)) A GetA() 
{ 
    A const a; 
    return a; 
} 

int main() 
{ 
    IGNORE_RESULT(GetA()); 
    return 0; 
} 
+4

No * uso * para usar C, pero prefiero C a C++ :) –

+0

Desearía poder votar ese comentario más de una vez ;-) – Mawg