2011-01-21 10 views
5

En realidad tengo una solución a este problema, pero me pregunto si hay uno más liviano.¿Cómo suprimo la salida mientras uso una biblioteca dinámica?

Tengo la necesidad de cargar en una biblioteca a mi utilidad usando dlopen y luego llamar a una de las funciones.

Desafortunadamente, la función arroja una gran cantidad de información en STDOUT y esto no quiero.

Tengo una solución que no es portátil y me pregunto si existe una solución mejor y más genérica que pueda utilizar.

Esto es lo que tengo (NB : Este es C):

/* 
* Structure for retaining information about a stream, sufficient to 
* recreate that stream later on 
*/ 
struct stream_info { 
    int fd; 
    fpos_t pos; 
}; 
#define STDOUT_INFO 0 
#define STDERR_INFO 1 

struct stream_info s_info[2]; 
point_stream_to_null(stdout, &s_info[STDOUT_INFO]); 
point_stream_to_null(stderr, &s_info[STDERR_INFO]); 

void *output = noisy_function(); 

reset_stream(stderr, &s_info[STDERR_INFO]); 
reset_stream(stdout, &s_info[STDOUT_INFO]); 

/* 
* Redirects a stream to null and retains sufficient information to restore the stream to its original location 
*** NB *** 
* Not Portable 
*/ 
void point_stream_to_null(FILE *stream, struct stream_info *info) { 
    fflush(stream); 
    fgetpos(stream, &(info->pos)); 
    info->fd = dup(fileno(stream)); 
    freopen("/dev/null", "w", stream); 
} 

/* 
* Resets a stream to its original location using the info provided 
*/ 
void reset_stream(FILE *stream, struct stream_info *info) { 
    fflush(stream); 
    dup2(info->fd, fileno(stream)); 
    close(info->fd); 
    clearerr(stream); 
    fsetpos(stream, &(info->pos)); 
} 

¿Alguna sugerencia?

+0

Windows o Unix? – Spaceghost

+0

buscando una solución portátil. Lo que tengo está bien para Unix. – Dancrumb

Respuesta

2

Tengo una sugerencia, que le permite usar el preprocesador para la portabilidad, o tal vez "portabilidad".

Si intenta algo así como

#if defined __unix__ 
#define DEVNULL "/dev/null" 
#elif defined _WIN32 
#define DEVNULL "nul" 
#endif 

(haciendo caso omiso de otros sistemas operativos, caso más, la directiva de error, etc.) y vuelva a abrir el archivo como antes

FILE *myfile = freopen(DEVNULL, "w", stream); 

entonces que le brinde Lo que quieras.

No he probado esto en casa, sin embargo. El archivo "nul" existe; ver /dev/null in Windows. Y puede obtener macros predefinidas al "Pre-defined C/C++ Compiler Macros".

+0

Gracias JXG: Eso es lo más cercano que tengo a una respuesta portátil ... Tomaré "portátil" cualquier día :) – Dancrumb

0

En Windows se pueden redireccionar las secuencias de transmisión también. Ver http://support.microsoft.com/kb/110930/en-us

+0

Esas redirecciones son redirecciones de shell. Como resultado, esto no hace nada para separar mi salida deseada de la basura no deseada que genera la función de biblioteca. – Dancrumb

0

Desafortunadamente, la apertura a un nombre de archivo nulo específico de la plataforma es lo más parecido que se puede obtener en la norma C. También podría considerar modificar la biblioteca para no generar tanta salida en stdout.

Dicho esto, en la práctica, los únicos sistemas operativos de los que debe preocuparse son basados ​​en Unix (incluido MacOS) o Windows: en el caso de Windows, stdout está oculto de forma predeterminada, por lo que puede omitir el paso de redirección , y para * nix ya tienes el código.

+0

¿Puedes aclarar que 'stdout está oculto por defecto'? ¿A dónde se dirige printf en ese caso? – Dancrumb

+0

A menos que tenga un depurador conectado, o alguien se tome la molestia de adjuntarlo a su estándar, o inicialice una consola, en una aplicación de subsistema Win32 todo lo que se envía a stdout se descarta de manera predeterminada. – bdonlan

+0

Entendido. Sin embargo, la utilidad se ejecuta desde el símbolo del sistema, por lo que siempre tenemos una consola conectada a STDOUT – Dancrumb

0

noisy_function ejecutará algunos códigos de escritura en la salida estándar; no puede detener noisy_function haciendo eso.

Lo que necesita hacer es evitar que los datos introducidos en stdout vayan a quién está escuchando su salida, pero dudo que haya una forma portátil de hacerlo.

Cerraría (redirigiría a /dev/null) salida estándar mientras lo hace, esa es la manera más fácil de cerrar noisy_function; Otra solución (aún no portátil) podría ser la de fork ing y dejar que el niño procese la llamada al noisy_function.

2

Puede intentar usar setvbuf para establecer stdout para tener un búfer muy grande y estar completamente amortiguado. Luego, después de cada llamada al noisy_function, elimine el búfer antes de enjuagarlo. Sin embargo, creo que esto invoca un comportamiento indefinido.

Otra forma sería redirigir stdout a un archivo temporal, como con esta función de macro.

#include <stdio.h> 

#define QUIET_CALL(noisy) { \ 
    FILE* tmp = stdout;\ 
    stdout = tmpfile();\ 
    (noisy);\ 
    fclose(stdout);\ 
    stdout = tmp;\ 
} 

int main(){ 
    QUIET_CALL(printf("blah blah")); 
    printf("bloo bloo\n"); 
    return 0; 
} 
+0

¡Impresionante! Funciona como magia ¡Gracias! – Pojo

Cuestiones relacionadas