2012-08-29 17 views
6

Tengo una funcionalidad de informe de errores en mi pequeña biblioteca de C que estoy escribiendo. Deseo proporcionar una función errorf además de la función simple error para permitir la incrustación de información en mensajes de error fácilmente.Evitar advertencias en el contenedor de printf

/* 
* Prints a formatted error message. Use it as you would use 'printf'. See the 
* 'sio_error' function. 
*/ 
void sio_errorf(const char *format, ...) { 
    // Print the error prefix       
    if (g_input == STDIN) fputs("error: ", stderr); 
    else fprintf(stderr, "%s: ", g_progname); 

    // Pass on the varargs on to 'vfprintf'. 
    va_list arglist; 
    va_start(arglist, format); 
    // This may produce the following warning -- ignore it: 
    //  warning: format string is not a string literal 
    vfprintf(stderr, format, arglist); 
    va_end(arglist); 
    fputc('\n', stderr); 
} 

El problema es, consigo esta advertencia (Compilación con sonido metálico 4.0 con el interruptor -Weverything):

advertencia: cadena de formato no es una cadena literal

entiendo por qué hacer esto sería malo. ¿Hay alguna forma de que pueda deshacerme de esta advertencia? ¿Puedo de alguna manera exigir que el argumento formatsio_errorf sea un literal de cadena, para que el compilador sepa que siempre lo estará y que simplemente lo estoy transmitiendo?

Sé que puedo usar -Wno-format-nonliteral, pero solo si otras personas van a compilarlo manualmente también, no lo harán. Prefiero algo en el código fuente que silencie la advertencia.

Idealmente aún recibiría la advertencia si la secuencia que pasé a sio_errorfen realidad no es literal, pero no estoy seguro si eso es posible.

+1

Qué compilador, y qué versión, está usando? –

+0

Clang ('-v' me dice" Apple clang versión 4.0 "), aunque estoy bastante seguro de que gcc da la misma advertencia. – mk12

Respuesta

9

Si está utilizando GCC o uno de sus parientes, tratar un atributo en la declaración:

void sio_errorf(const char *format, ...) __attribute__((format(printf, 1, 2))); 

Para añadir el atributo a una definición, puede utilizar esto:

__attribute__((format(printf, 1, 2))) 
    static void sio_errorf(const char *format, ...) { 
     .... 
+2

¡Buena idea! Esto es específicamente proporcionado por GCC para estas situaciones. – Linuxios

+0

¿Esto solo pasa al prototipo de función en el encabezado? No en la definición? – mk12

+0

@ Mk12 también puede aplicarlo a una definición: '__attribute __ ((format (printf, 1, 2))) static void sio_errorf2 (formato const char *, ...) {\ n ...'. pero si el atributo no es visible en la traducción, entonces el compilador no verificará su formato/parámetros. (Actualizará la respuesta) – justin

8

Muchos compiladores le permitirán establecer niveles de advertencia de una forma u otra. Por ejemplo, gcc permite el control a través de indicadores -W en la línea de comando cuando se invoca el compilador.

Esperamos que ese es el compilador que está utilizando desde un programa como este:

#include <stdio.h> 
int main (void) { 
    char *s = "xyzzy\n"; 
    printf (s); 
    return 0; 
} 

genera el mensaje exacto describes (suponiendo que haya habilitado las advertencias con -Wformat y -Wformat-nonliteral).

El argumento de línea de comando en particular que se busca es para:

-Wno-format-nonliteral 

lo que evitará que las quejas sobre el uso de cadenas no literales en esas funciones.

Sin embargo, usted puede estar buscando algo más de grano fino por lo que también le permite especificar la disposición de ciertos mensajes de diagnóstico sobre la marcha dentro el código con pragmas:

#include <stdio.h> 
#pragma GCC diagnostic ignored "-Wformat-nonliteral" 
int main (void) { 
    char *s = "xyzzy\n"; 
    printf (s); 
    return 0; 
} 
#pragma GCC diagnostic warning "-Wformat-nonliteral" 

Si compila que con -Wformat -Wformat-nonliteral, no se vea la advertencia, porque le indicó a gcc que ignore esa advertencia en particular para la función main.

Las versiones posteriores de gcc que el corro tienen las siguientes opciones:

#pragma GCC diagnostic push 
#pragma GCC diagnostic pop 

que empujar y hacer estallar el estado de los diagnósticos. Esto soluciona los problemas en mi código anterior donde podría configurar esa advertencia como un error - mi segundo pragma lo convertiría en una advertencia.

El uso de push/pop permitiría la restauración a su disposición original con algo como:

#include <stdio.h> 
#pragma GCC diagnostic push 
#pragma GCC diagnostic ignored "-Wformat-nonliteral" 
int main (void) { 
    char *s = "xyzzy\n"; 
    printf (s); 
    return 0; 
} 
#pragma GCC diagnostic pop 
+0

En cuanto a la primera parte de su respuesta, lo siento, debería haber mencionado que ya sé que puedo usar '-Wno-format-nonliteral'. Sin embargo, no puedo obligar a los demás a hacerlo. Prefiero ser capaz de compilar con '-Weverything' y no tener advertencias. – mk12

+0

Sin embargo, la segunda parte de tu respuesta parece lo que quiero. Actualmente lo estoy comparando con la respuesta de Justin. – mk12

Cuestiones relacionadas