Cómo deshabilitar las advertencias de GCC para algunas líneas de código

220

En Visual C ++, es posible usarlo #pragma warning (disable: ...). También descubrí que en GCC puede anular las banderas del compilador por archivo . ¿Cómo puedo hacer esto para la "línea siguiente", o con semántica push / pop alrededor de áreas de código usando GCC?

Matt Joiner
fuente
1
posible duplicado de deshabilitar advertencias específicas en gcc - Vaya, en realidad esa pregunta en sí misma es un engaño (pero no cerrado). Simplemente es el que apareció en "Relacionado". De todos modos, esto se ha preguntado y respondido varias veces en SO.
Tyler McHenry
1
@paxdiablo: estoy haciendo lo contrario. Elevé el nivel de advertencia muy alto y quiero aplastar las advertencias línea por línea que verifiqué que están bien.
Matt Joiner
44
@Tyler McHenry: si lo revisó con más cuidado, podría notar que la pregunta vinculada contiene una solución por archivo, precisamente la que mencioné en mi propia pregunta como insatisfactoria (incluso robé el enlace).
Matt Joiner
66
@paxdiablo, los compiladores dan falsos positivos, a veces desea compilar con -Werror pero no hacer que estos falsos positivos bloqueen una compilación. entonces deshabilitar casos específicos y comentar por qué tiene sentido en algunos casos. También hay otros casos en los que esto podría ser útil, como el código de generación automática que produce advertencias inofensivas que no son tan fáciles de ingresar y cambiar (ya que se genera el código), aunque en ese caso es más probable que la desactivación por archivo la solución.
ideasman42

Respuestas:

221

Parece que esto se puede hacer . No puedo determinar la versión de GCC que se agregó, pero fue en algún momento antes de junio de 2010.

Aquí hay un ejemplo:

#pragma GCC diagnostic error "-Wuninitialized"
    foo(a);         /* error is given for this one */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuninitialized"
    foo(b);         /* no diagnostic for this one */
#pragma GCC diagnostic pop
    foo(c);         /* error is given for this one */
#pragma GCC diagnostic pop
    foo(d);         /* depends on command line options */
Matt Joiner
fuente
14
uno pushy dos pops - puede ser otro pushal principio falta?
abyss.7
37
"#pragma GCC diagnóstico push #pragma GCC diagnosis emergente Hace que GCC recuerde el estado de los diagnósticos a cada inserción y se restaure a ese punto en cada pop. Si un pop no tiene una coincidencia, las opciones de la línea de comandos se restauran. " - del manual de GCC: gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
bobpaul
11
Como referencia, gcc versión 4.4.3 admite error / advertencia / ignorado, pero no push / pop
frankster
12
La primera versión de GCC que tenía push / pop de diagnóstico es GCC 4.6.4 . Determiné esto mirando la sección Diagnostic-Pragmas.html # Diagnostic-Pragmas para cada versión de GCC
bitek
55
Es una pena que esto no funcione en la práctica. En algunos casos, produce más advertencias. O tal vez, más correctamente, no funciona en la práctica para GCC 4.7 a 5.1. Ver, por ejemplo, GCC no respeta el 'diagnóstico de pragma GCC' para silenciar las advertencias .
jww
108

Para eliminar todo, este es un ejemplo de deshabilitar temporalmente una advertencia:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
    write(foo, bar, baz);
#pragma GCC diagnostic pop

Puede consultar la documentación de GCC sobre pragmas de diagnóstico para obtener más detalles.

Ian Pilcher
fuente
2
Debería funcionar, pero mi gcc-4.9solo ignora esta línea por completo.
Aleksei Petrenko
31

TL; DR : si funciona, evite o use especificadores como __attribute__, de lo contrario _Pragma.

Esta es una versión corta del artículo de mi blog Suprimir advertencias en GCC y Clang .

Considera lo siguiente Makefile

CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror

.PHONY: all
all: puts

para construir el siguiente puts.ccódigo fuente

#include <stdio.h>

int main(int argc, const char *argv[])
{
    while (*++argv) puts(*argv);
    return 0;
}

No se compilará porque argcno se usa, y la configuración es hardcore ( -W -Wall -pedantic -Werror).

Hay 5 cosas que puedes hacer:

  • Mejora el código fuente, si es posible
  • Use un especificador de declaración, como __attribute__
  • Utilizar _Pragma
  • Utilizar #pragma
  • Use una opción de línea de comando.

Mejorando la fuente

El primer intento debe ser verificar si el código fuente se puede mejorar para deshacerse de la advertencia. En este caso, no queremos cambiar el algoritmo solo por eso, ya que argces redundante con !*argv( NULLdespués del último elemento).

Usando un especificador de declaración, como __attribute__

#include <stdio.h>

int main(__attribute__((unused)) int argc, const char *argv[])
{
    while (*++argv) puts(*argv);
    return 0;
}

Si tiene suerte, el estándar proporciona un especificador para su situación, como _Noreturn.

__attribute__es una extensión patentada de GCC (también compatible con Clang y algunos otros compiladores armcc) y muchos otros compiladores no la entenderán. Poner __attribute__((unused))dentro de una macro si quieres un código portátil.

_Pragma operador

_Pragmase puede usar como una alternativa a #pragma.

#include <stdio.h>

_Pragma("GCC diagnostic push")
_Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")

int main(int argc, const char *argv[])
{
    while (*++argv) puts(*argv);
    return 0;
}
_Pragma("GCC diagnostic pop")

La principal ventaja del _Pragmaoperador es que puede colocarlo dentro de macros, lo cual no es posible con la #pragmadirectiva.

Desventaja: es casi un arma nuclear táctica, ya que funciona en línea en lugar de en la declaración.

El _Pragmaoperador se introdujo en C99.

#pragma directiva.

Podríamos cambiar el código fuente para suprimir la advertencia de una región de código, generalmente una función completa:

#include <stdio.h>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
int main(int argc, const char *argv[])
{
    while (*++argc) puts(*argv);
    return 0;
}
#pragma GCC diagnostic pop

Desventaja: es casi un arma nuclear táctica, ya que funciona en línea en lugar de en la declaración.

Tenga en cuenta que existe una sintaxis similar en clang .

Suprimir la advertencia en la línea de comando para un solo archivo

Podríamos agregar la siguiente línea al Makefilepara suprimir la advertencia específicamente para los put:

CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror

.PHONY: all
all: puts

puts.o: CPPFLAGS+=-Wno-unused-parameter

Probablemente no sea lo que quiere en su caso particular, pero puede ayudar a otras lecturas que se encuentran en situaciones similares.

Christian Hujer
fuente
2
re: improving the sourcetambién funcionaría cambiar la declaración de main al int main(int, const char* argv[]) { ... }no darle un nombre al argumento, le dice al compilador que no se usará.
Jesse Chisholm el
1
@JesseChisholm omitir el nombre del parámetro en la definición de la función no es posible. Ver 6.9.1 definintions función de la norma ISO / IEC9899, § 5 "Si el declarador incluye una lista de tipos de parámetros, la declaración de cada parámetro debe incluir un identificador [...]" Y correctamente lo que el código sería rechazado por gcc, así como clang.
Christian Hujer
1
Otro patrón es simplemente hacer un reparto de la variable para anular. De hecho, he visto en un proyecto la siguiente macro: #define UNUSED(x) ((void)x)utilizada para silenciar advertencias. Creo que fue en ReactOS?
Paul Stelian
1
No creo que necesites la barra invertida después de esto, ¿no? _Pragma("GCC diagnostic pop") \ debería ser _Pragma("GCC diagnostic pop"), creo.
Gabriel Staples
1
@GabrielStaples Eso es correcto, gracias por notarlo, he actualizado la respuesta.
Christian Hujer
20
#define DIAG_STR(s) #s
#define DIAG_JOINSTR(x,y) DIAG_STR(x ## y)
#ifdef _MSC_VER
#define DIAG_DO_PRAGMA(x) __pragma (#x)
#define DIAG_PRAGMA(compiler,x) DIAG_DO_PRAGMA(warning(x))
#else
#define DIAG_DO_PRAGMA(x) _Pragma (#x)
#define DIAG_PRAGMA(compiler,x) DIAG_DO_PRAGMA(compiler diagnostic x)
#endif
#if defined(__clang__)
# define DISABLE_WARNING(gcc_unused,clang_option,msvc_unused) DIAG_PRAGMA(clang,push) DIAG_PRAGMA(clang,ignored DIAG_JOINSTR(-W,clang_option))
# define ENABLE_WARNING(gcc_unused,clang_option,msvc_unused) DIAG_PRAGMA(clang,pop)
#elif defined(_MSC_VER)
# define DISABLE_WARNING(gcc_unused,clang_unused,msvc_errorcode) DIAG_PRAGMA(msvc,push) DIAG_DO_PRAGMA(warning(disable:##msvc_errorcode))
# define ENABLE_WARNING(gcc_unused,clang_unused,msvc_errorcode) DIAG_PRAGMA(msvc,pop)
#elif defined(__GNUC__)
#if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406
# define DISABLE_WARNING(gcc_option,clang_unused,msvc_unused) DIAG_PRAGMA(GCC,push) DIAG_PRAGMA(GCC,ignored DIAG_JOINSTR(-W,gcc_option))
# define ENABLE_WARNING(gcc_option,clang_unused,msvc_unused) DIAG_PRAGMA(GCC,pop)
#else
# define DISABLE_WARNING(gcc_option,clang_unused,msvc_unused) DIAG_PRAGMA(GCC,ignored DIAG_JOINSTR(-W,gcc_option))
# define ENABLE_WARNING(gcc_option,clang_option,msvc_unused) DIAG_PRAGMA(GCC,warning DIAG_JOINSTR(-W,gcc_option))
#endif
#endif

Esto debería hacer el truco para gcc, clang y msvc

Se puede llamar con, por ejemplo:

DISABLE_WARNING(unused-variable,unused-variable,42)
[.... some code with warnings in here ....]
ENABLE_WARNING(unused-variable,unused-variable,42)

ver https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html , http://clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmas y https://msdn.microsoft .com / de-DE / library / d9x1s805.aspx para más detalles

Necesita al menos la versión 4.02 para usar este tipo de pragmas para gcc, no estoy seguro acerca de msvc y clang acerca de las versiones.

Parece que el manejo del pragma push pop para gcc está un poco roto. Si habilita la advertencia nuevamente, aún obtiene la advertencia para el bloque que estaba dentro del bloque DISABLE_WARNING / ENABLE_WARNING. Para algunas versiones de gcc funciona, para algunas no.

Martin Gerhardy
fuente
3
Eres un MVP real
zeboidlund
19
#pragma GCC diagnostic ignored "-Wformat"

Reemplace "-Wformat" con el nombre de su bandera de advertencia.

AFAIK no hay forma de usar la semántica push / pop para esta opción.

Joe D
fuente
44
Es una pena que esto no funcione en la práctica. En algunos casos, produce más advertencias. O tal vez, más correctamente, no funciona en la práctica para GCC 4.7 a 5.1. Ver, por ejemplo, GCC no respeta el 'diagnóstico de pragma GCC' para silenciar las advertencias .
jww
6

Tuve el mismo problema con las bibliotecas externas como los encabezados ROS. Me gusta usar las siguientes opciones en CMakeLists.txt para una compilación más estricta:

set(CMAKE_CXX_FLAGS "-std=c++0x -Wall -Wextra -Wstrict-aliasing -pedantic -Werror -Wunreachable-code ${CMAKE_CXX_FLAGS}")

Sin embargo, hacer esto también causa todo tipo de errores pedantes en bibliotecas incluidas externamente. La solución es desactivar todas las advertencias pedantes antes de incluir bibliotecas externas y volver a habilitarlas así:

//save compiler switches
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"

//Bad headers with problem goes here
#include <ros/ros.h>
#include <sensor_msgs/LaserScan.h>

//restore compiler switches
#pragma GCC diagnostic pop
Shital Shah
fuente
2
¿No debería manejarse mejor con los directorios del sistema de gcc ?
Rojo XIII
@RedXIII: sí, esa es una opción si puede hacer una lista de dichos directorios y especificar en la línea de comando gcc. Sin embargo, muchas veces el compilador se invoca profundamente en la tubería o no tienes mucho control sobre cómo alguien más debe compilar tu código. En esos casos anteriores es probablemente una mejor solución.
Shital Shah
5

Sé que la pregunta es sobre GCC, pero para las personas que buscan cómo hacer esto en otros y / o compiladores múltiples ...

TL; DR

Es posible que desee echar un vistazo a Hedley , que es un encabezado C / C ++ de dominio público que escribí y que hace muchas de estas cosas por usted. Pondré una sección rápida sobre cómo usar Hedley para todo esto al final de esta publicación.

Deshabilitar la advertencia

#pragma warning (disable: …) tiene equivalentes en la mayoría de los compiladores:

  • MSVC: #pragma warning(disable:4996)
  • CCG: #pragma GCC diagnostic ignored "-W…"donde la elipsis es el nombre de la advertencia; por ejemplo , #pragma GCC diagnostic ignored "-Wdeprecated-declarations.
  • tañido: #pragma clang diagnostic ignored "-W…". La sintaxis es básicamente la misma que la de GCC y muchos de los nombres de advertencia son los mismos (aunque muchos no lo son).
  • Compilador Intel C: use la sintaxis MSVC, pero tenga en cuenta que los números de advertencia son totalmente diferentes. Ejemplo: #pragma warning(disable:1478 1786).
  • PGI: Hay un diag_suppresspragma:#pragma diag_suppress 1215,1444
  • TI: Hay un diag_suppresspragma con la misma sintaxis (¡pero diferentes números de advertencia!) Que PGI:pragma diag_suppress 1291,1718
  • Oracle Developer Studio (suncc): hay un error_messagespragma. Molesto, las advertencias son diferentes para los compiladores C y C ++. Ambos deshabilitan básicamente las mismas advertencias:
    • C: #pragma error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)
    • C ++: #pragma error_messages(off,symdeprecated,symdeprecated2)
  • IAR: también se usa diag_suppresscomo PGI y TI, pero la sintaxis es diferente. Algunos de los números de advertencia son los mismos, pero otros han divergido:#pragma diag_suppress=Pe1444,Pe1215
  • Pelles C: similar a MSVC, aunque nuevamente los números son diferentes #pragma warn(disable:2241)

Para la mayoría de los compiladores, a menudo es una buena idea verificar la versión del compilador antes de intentar deshabilitarla, de lo contrario, terminará activando otra advertencia. Por ejemplo, GCC 7 agregó soporte para la -Wimplicit-fallthroughadvertencia, así que si te importa GCC antes de 7 deberías hacer algo como

#if defined(__GNUC__) && (__GNUC__ >= 7)
#  pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif

Para clang y compiladores basados ​​en clang, como las versiones más nuevas de XL C / C ++ y armclang, puede verificar si el compilador conoce una advertencia particular utilizando la __has_warning()macro.

#if __has_warning("-Wimplicit-fallthrough")
#  pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#endif

Por supuesto, también debe verificar si __has_warning()existe la macro:

#if defined(__has_warning)
#  if __has_warning("-Wimplicit-fallthrough")
#    pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#  endif
#endif

Puede sentirse tentado a hacer algo como

#if !defined(__has_warning)
#  define __has_warning(warning)
#endif

Para que pueda usar __has_warningun poco más fácilmente. Clang incluso sugiere algo similar para la __has_builtin()macro en su manual. No hagas esto . Otro código puede verificar __has_warningy recurrir a verificar las versiones del compilador si no existe, y si usted define __has_warning, romperá su código. La forma correcta de hacer esto es crear una macro en su espacio de nombres. Por ejemplo:

#if defined(__has_warning)
#  define MY_HAS_WARNING(warning) __has_warning(warning)
#else
#  define MY_HAS_WARNING(warning) (0)
#endif

Entonces puedes hacer cosas como

#if MY_HAS_WARNING(warning)
#  pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#elif defined(__GNUC__) && (__GNUC__ >= 7)
#  pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif

Empujando y haciendo estallar

Muchos compiladores también admiten una forma de enviar y desplegar advertencias en una pila. Por ejemplo, esto deshabilitará una advertencia en GCC para una línea de código, luego la devolverá a su estado anterior:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
call_deprecated_function();
#pragma GCC diagnostic pop

Por supuesto, no hay mucho acuerdo entre los compiladores sobre la sintaxis:

  • GCC 4.6+: #pragma GCC diagnostic push/#pragma GCC diagnostic pop
  • Clang: #pragma clang diagnostic push/#pragma diagnostic pop
  • Intel 13+ (y probablemente anterior): #pragma warning(push)/#pragma warning(pop)
  • MSVC 15+ (VS 9.0 / 2008): #pragma warning(push)/#pragma warning(pop)
  • BRAZO 5.6+: #pragma push/#pragma pop
  • TI 8.1+: #pragma diag_push/#pragma diag_pop
  • Pelles C 2.90+ (y probablemente antes): #pragma warning(push)/#pragma warning(pop)

Si la memoria funciona, para algunas versiones muy antiguas de GCC (como 3.x, IIRC), los pragmas push / pop tenían que estar fuera de la función.

Ocultando los detalles sangrientos

Para la mayoría de los compiladores es posible ocultar la lógica detrás del uso de macros _Pragma, que se introdujo en C99. Incluso en modo no C99, la mayoría de los compiladores son compatibles _Pragma; La gran excepción es MSVC, que tiene su propia __pragmapalabra clave con una sintaxis diferente. El estándar _Pragmatoma una cadena, la versión de Microsoft no:

#if defined(_MSC_VER)
#  define PRAGMA_FOO __pragma(foo)
#else
#  define PRAGMA_FOO _Pragma("foo")
#endif
PRAGMA_FOO

Es aproximadamente equivalente, una vez preprocesado, a

#pragma foo

Esto nos permite crear macros para que podamos escribir código como

MY_DIAGNOSTIC_PUSH
MY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated_function();
MY_DIAGNOSTIC_POP

Y esconda todas las verificaciones de versiones feas en las definiciones de macro.

La manera fácil: Hedley

Ahora que comprende la mecánica de cómo hacer cosas como esta de forma portátil mientras mantiene limpio su código, comprende lo que hace uno de mis proyectos, Hedley . En lugar de buscar toneladas de documentación y / o instalar tantas versiones de tantos compiladores como pueda probar, puede incluir Hedley (es un encabezado C / C ++ de dominio público único) y listo. Por ejemplo:

#include "hedley.h"

HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated();
HEDLEY_DIAGNOSTIC_POP

Deshabilitará la advertencia acerca de llamar a una función obsoleta en GCC, clang, ICC, PGI, MSVC, TI, IAR, ODS, Pelles y posiblemente otras (probablemente no me moleste en actualizar esta respuesta mientras actualizo Hedley). Y, en los compiladores que no se sabe que funcionan, las macros se procesarán previamente a cero, por lo que su código seguirá funcionando con cualquier compilador. Por supuesto, HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATEDno es la única advertencia que Hedley conoce, ni las advertencias de desactivación son todo lo que Hedley puede hacer, pero espero que entiendas la idea.

nemequ
fuente
3

En lugar de silenciar las advertencias, el estilo gcc generalmente es usar construcciones C estándar o la __attribute__extensión para contarle al compilador más sobre su intención. Por ejemplo, la advertencia sobre la asignación utilizada como condición se suprime al poner la asignación entre paréntesis, es decir, en if ((p=malloc(cnt)))lugar de if (p=malloc(cnt)). Las advertencias sobre argumentos de funciones no utilizadas pueden ser suprimidas por alguna extraña __attribute__que nunca recuerdo, o por autoasignación, etc. Pero generalmente prefiero simplemente deshabilitar globalmente cualquier opción de advertencia que genere advertencias para cosas que ocurrirán en el código correcto.

R .. GitHub DEJA DE AYUDAR AL HIELO
fuente
2
Tal vez sea así. Mi intención no es probar ningún patrón de caso general, sino una observación sobre cuál es la filosofía de gcc sobre la supresión de advertencia.
R .. GitHub DEJA DE AYUDAR AL HIELO
El compilador se comporta de manera diferente con advertencias de t / r / t con paréntesis añadidos?!?! ?? !!!! ¡GUAUU! Eso es inesperado
Jason S
1
@JasonS the parens no cambia el comportamiento del compilador wrt advertencias, lo que hace es cambiar la semántica de la declaración. Los elementos parentales adicionales hacen que el compilador finalice la asignación y mantenga su valor final como una expresión, lo que no merece ninguna advertencia. Si quieres claridad, podrías decir if ((p=malloc(cnt)) != NULL) ...que eso es lo que el compilador está haciendo detrás de escena.
Jesse Chisholm
@JesseChisholm: No creo que su explicación sea precisa.
R .. GitHub DEJA DE AYUDAR AL HIELO el
3

Para aquellos que encontraron esta página buscando una manera de hacer esto en IAR, intente esto:

#pragma diag_suppress=Pe177
void foo1( void )
{
   /* The following line of code would normally provoke diagnostic 
      message #177-D: variable "x" was declared but never referenced.
      Instead, we have suppressed this warning throughout the entire 
      scope of foo1(). 
   */
   int x;
}
#pragma diag_default=Pe177

Consulte http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472m/chr1359124244797.html como referencia.

Keron
fuente