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

15 minutos de lectura

avatar de usuario
carpintero mate

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

  • posible duplicado de deshabilitar advertencias específicas en gcc – Ups, en realidad esa pregunta en sí es un engaño (pero no cerrada). Resulta que ese es el que apareció en “Relacionado”. De todos modos, esto se ha preguntado y respondido varias veces en SO.

    – Tyler McHenry

    31 de julio de 2010 a las 14:49


  • @paxdiablo: Estoy haciendo lo contrario. He aumentado el nivel de advertencia muy alto y quiero aplastar las advertencias línea por línea que he verificado que están bien.

    – Matt Carpintero

    31 de julio de 2010 a las 16:28

  • @Tyler McHenry: si revisó con más cuidado, puede 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 Carpintero

    31 de julio de 2010 a las 16:30


  • @paxdiablo, los compiladores dan falsos positivos, a veces desea compilar con -Werror pero que estos falsos positivos no bloqueen una compilación. por lo tanto, 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 deshabilitar por archivo la solución.

    – ideasman42

    4 de noviembre de 2012 a las 6:56

avatar de usuario
carpintero mate

parece 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 */

  • uno push y dos pops – puede ser otro push al principio falta?

    – abismo.7

    17 de noviembre de 2012 a las 14:03

  • “#pragma GCC push de diagnóstico #pragma GCC pop de diagnóstico Hace que GCC recuerde el estado de los diagnósticos en cada pulsación y restaure a ese punto en cada pulsación. Si una pulsación no coincide con la pulsación, se restauran las opciones de la línea de comandos. ” — del manual de GCC: gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html

    – bobpaul

    11 de enero de 2013 a las 18:43

  • Como referencia, la versión 4.4.3 de gcc admite error/advertencia/ignorado, pero no push/pop

    – Frankster

    12 de febrero de 2013 a las 14:21

  • La primera versión de GCC que tenía push/pop de diagnóstico es CCG 4.6.4. Lo determiné mirando la sección Diagnostic-Pragmas.html#Diagnostic-Pragmas para cada versión de GCC en Documentación del CCG

    – Alex Bitek

    20 de agosto de 2014 a las 15:48


  • 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. Véase, por ejemplo, GCC no respeta el ‘diagnóstico pragma GCC’ para silenciar las advertencias.

    – jww

    20 de julio de 2015 a las 7:05

avatar de usuario
Ian Pillcher

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

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

Puedes comprobar el Documentación de GCC sobre pragmas de diagnóstico para más detalles.

  • Debería funcionar, pero mi gcc-4.9 simplemente ignora esta línea por completo.

    – Alekséi Petrenko

    18 de septiembre de 2017 a las 13:42

avatar de usuario
cristian hujer

TL;RD: si funciona, evítelo o use especificadores como __attribute__de lo contrario _Pragma.

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

Considera lo siguiente Makefile,

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

.PHONY: all
all: puts

para construir lo siguiente puts.c código fuente:

#include <stdio.h>

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

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

Hay cinco cosas que podrías hacer:

  • Mejorar el código fuente, si es posible.
  • Use un especificador de declaración, como __attribute__
  • Usar _Pragma
  • Usar #pragma
  • Utilice una opción de línea de comandos.

Mejorando la fuente

El primer intento debe ser verificar si el código fuente se puede mejorar para eliminar la advertencia. En este caso no queremos cambiar el algoritmo solo por eso, ya que argc es redundante con !*argv (NULL despué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 GCC propietaria (compatible con Clang y algunos otros compiladores como armcc también) y no será entendido por muchos otros compiladores. Poner __attribute__((unused)) dentro de una macro si quieres un código portátil.

_Pragma operador

_Pragma se puede utilizar como 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 de la _Pragma operador es que podría ponerlo dentro de macros, lo cual no es posible con el #pragma directiva.

Desventaja: es casi una bomba nuclear táctica, ya que funciona basado en líneas en lugar de en declaraciones.

Él _Pragma El operador fue introducido en C99.

#pragma directiva.

Podríamos cambiar el código fuente para suprimir la advertencia de una región de código, normalmente 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 una bomba nuclear táctica, ya que funciona basado en líneas en lugar de en declaraciones.

Tenga en cuenta que existe una sintaxis similar en Clang.

Supresión de la advertencia en la línea de comando para un solo archivo

Podríamos agregar la siguiente línea al Makefile para suprimir la advertencia específicamente para puts:

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

.PHONY: all
all: puts

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

Probablemente esto no sea lo que usted quiere en su caso particular, pero puede ayudar a otros lectores que se encuentran en situaciones similares.

  • re: improving the source también funcionaría cambiar la declaración de main a int main(int, const char* argv[]) { ... } al no darle un nombre al argumento, le dice al compilador que no se usará.

    – Jesse Chisholm

    09/08/2018 a las 18:05

  • @JesseChisholm no es posible omitir el nombre del parámetro en la definición de la función. Ver 6.9.1 Definiciones de funciones de 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 por lo que el código sería rechazado por gcc así como clang.

    – Christian Hujer

    29 de noviembre de 2018 a las 17:33

  • Otro patrón es simplemente hacer una conversión de la variable a anular. De hecho, he visto en un proyecto la siguiente macro: #define UNUSED(x) ((void)x) utilizado para silenciar las advertencias. Creo que fue en ReactOS?

    –Paul Stelian

    13 de abril de 2019 a las 15:11


  • Ellos camino __attribute__ la sintaxis funciona, utiliza inteligentemente paréntesis dobles (( ))entonces, si su compilador no lo entiende, puede #define __attribute__(x) y todos desaparecen.

    – doug65536

    15 de junio de 2021 a las 4:14

avatar de usuario
nemequ

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

TL;RD

Es posible que desee echar un vistazo a Hedleyque es un encabezado C/C++ único de dominio público que escribí y que hace un lote de estas cosas para ti. 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 los puntos suspensivos son el nombre de la advertencia; p.ej, #pragma GCC diagnostic ignored "-Wdeprecated-declarations.
  • Sonido metálico: #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++ (ICC): use la sintaxis de MSVC, pero tenga en cuenta que los números de advertencia son totalmente diferentes. Ejemplo: #pragma warning(disable:1478 1786).
  • IGP/Nvidia: Hay un diag_suppress pragma: #pragma diag_suppress 1215,1444. Tenga en cuenta que todos los números de advertencia aumentaron en uno en 20.7 (la primera Nvidia HPC liberación).
  • TI (CCS): Hay un diag_suppress pragma con la misma sintaxis (pero diferentes números de advertencia) como PGI: pragma diag_suppress 1291,1718
  • Estudio para desarrolladores de Oracle (ODS) (suncc): hay un error_messages pragma. Curiosamente, las advertencias son diferentes para los compiladores de 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 utiliza diag_suppress como 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 deshabilitarlo, de lo contrario, terminará activando otra advertencia. Por ejemplo, GCC 7 agregó soporte para el -Wimplicit-fallthrough advertencia, por lo que si te preocupa GCC antes de las 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 versiones más nuevas de XLC/C++ y armclang, puede verificar si el compilador conoce una advertencia en particular usando el __has_warning() macro.

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

Por supuesto, también hay que comprobar si el __has_warning() macro existe:

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

Usted puede estar tentado a hacer algo como

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

Entonces puedes usar __has_warning un poco más fácilmente. Clang incluso sugiere algo similar para el __has_builtin() macro en su manual. No hagas esto. Otro código puede verificar __has_warning y recurra a verificar las versiones del compilador si no existe, y si define __has_warning Romperás 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 insertar y mostrar advertencias en una pila. Por ejemplo, esto deshabilitará una advertencia en GCC para una línea de código y 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:

  • CCG 4.6+: #pragma GCC diagnostic push / #pragma GCC diagnostic pop
  • Sonido metálico: #pragma clang diagnostic push / #pragma diagnostic pop
  • Intel 13+ (y probablemente antes): #pragma warning(push) / #pragma warning(pop)
  • MSVC 15+ (Estudio visual 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 no me falla, para algunas versiones muy antiguas de GCC (como 3.x, IIRC) los pragmas push/pop tenían que ser fuera de la función

Ocultar los detalles sangrientos

Para la mayoría de los compiladores, es posible ocultar la lógica detrás de las macros usando _Pragmaque se introdujo en C99. Incluso en modo no C99, la mayoría de los compiladores admiten _Pragma; la gran excepción es MSVC, que tiene su propio __pragma palabra clave con una sintaxis diferente. El estandar _Pragma toma 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 más o menos 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 oculte todas las comprobaciones de versión 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 su código limpio, comprende cuál de mis proyectos, Hedley hace. En lugar de buscar en toneladas de documentación y/o instalar tantas versiones de tantos compiladores como pueda para probar, puede simplemente incluir Hedley (es un solo encabezado C/C++ de dominio público) y listo. Por ejemplo:

#include "hedley.h"

HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated();
HEDLEY_DIAGNOSTIC_POP

Deshabilitará la advertencia sobre llamar a una función obsoleta en GCC, Clang, ICC, PGI, MSVC, TI, IAR, ODS, Pelles C y posiblemente otros (probablemente no me molestaré en actualizar esta respuesta mientras actualizo a Hedley). Y, en los compiladores que no se sabe que funcionan, las macros se preprocesarán hasta quedar en nada, por lo que su código seguirá funcionando con cualquier compilador. Por supuesto HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED no es la única advertencia que conoce Hedley, ni tampoco desactivar las advertencias es todo lo que Hedley puede hacer, pero espero que entiendas la idea.

avatar de usuario
Martín Gerhardy

Usar:

#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, Sonido metálico 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 7 pragmas, Control de diagnósticos a través de Pragmas y Directivas pragma y las palabras clave __pragma y _Pragma para más detalles.

Necesita al menos la versión 4.02 para usar este tipo de pragmas para GCC, y no estoy seguro acerca de MSVC y Clang acerca de las versiones.

Parece que el manejo de pragma push pop para GCC está un poco roto. Si habilita la advertencia nuevamente, seguirá recibiendo la advertencia para el bloque que estaba dentro del bloque DISABLE_WARNING/ENABLE_WARNING. Para algunas versiones de GCC funciona y para otras no.

avatar de usuario
jose d

#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.

avatar de usuario
Pedro Mortensen

Tuve el mismo problema con bibliotecas externas como ROS encabezados 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 provoca todo tipo de errores pedantes en las bibliotecas incluidas externamente. La solución es deshabilitar todas las advertencias pedantes antes de incluir bibliotecas externas y volver a habilitarlas de esta manera:

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

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

// Restore compiler switches
#pragma GCC diagnostic pop

  • ¿No debería ser mejor manejar esto con gcc’s? sistema directorios?

    – Rojo XIII

    17 de enero de 2017 a las 10:19


  • @RedXIII: sí, esa es una opción si puede hacer una lista de dichos directorios y especificarlos en la línea de comandos de gcc. Sin embargo, muchas veces se invoca al compilador en lo profundo de la canalización o no tiene mucho control sobre cómo otra persona debe compilar su código. En los casos anteriores es probablemente una mejor solución.

    – Shital Shah

    2 de diciembre de 2019 a las 11:15

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad