Preprocesador C: expandir macro en una #advertencia

7 minutos de lectura

avatar de usuario
elomage

Me gustaría imprimir un valor de macro (expandir la macro) en la directiva #warning.

Por ejemplo, para el código:

#define AAA 17
#warning AAA = ???

La salida deseada en tiempo de compilación sería

warning: AAA = 17

¿¿Para qué uso???, o, ¿cómo aumento el código?

  • De acuerdo con el estándar C de 1999, solo tiene #error para algo así y no expande ninguna macro, simplemente imprime el texto literalmente y hace que la compilación se detenga. ¿Qué estás tratando de lograr con esto de todos modos?

    – Alexei Frunze

    28 de septiembre de 2012 a las 9:41

  • Tengo una jerarquía de muchos archivos MAKE que definen AAA de varias maneras, según los parámetros de destino de la marca. Me gustaría verificar que la definición es correcta para el objetivo. Y no quisiera crear una lista de #si AAA = 1… #advertencia “es 1″…

    – elomage

    28 de septiembre de 2012 a las 9:44


  • Además, esto es para el mundo incrustado sin pantallas, por lo que no puedo probar fácilmente el valor de la macro agregando algo como printf (#AAA); y comprobarlo en tiempo de ejecución.

    – elomage

    28 de septiembre de 2012 a las 9:58


  • Tu también #if A == 1\#error A = 1\#elif A == 2\#error A = 2\#endif.

    – Alexei Frunze

    28/09/2012 a las 10:00


  • @AlexeyFrunze Eso es exactamente lo que quiero evitar: vea mi comentario anterior. Puede que no sepa todos los valores posibles, o puede que haya demasiados.

    – elomage

    28 de septiembre de 2012 a las 10:09

avatar de usuario
moooeeeeep

Puedes usar la directiva del preprocesador #pragma message.

Ejemplo:

#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)

#define AAA 123
#pragma message "content of AAA: " STR(AAA)

int main() { return 0; }

La salida puede verse así:

$ gcc test.c
test.c:5:9: note: #pragma message: content of AAA: 123
 #pragma message("content of AAA: " STR(AAA))
         ^

Para referencia:

  • Debe mencionar los compiladores con los que funciona. #pragma's son específicos de la implementación.

    – Alexei Frunze

    28 de septiembre de 2012 a las 10:26


  • Funciona con gcc versión 4.5.3 (GNU GCC parcheado mspgcc-20110716), gracias.

    – elomage

    29 de septiembre de 2012 a las 13:11

  • asegúrese de usar #pragma message en lugar de #message o #warning

    – Fantasía

    7 de agosto de 2013 a las 9:57

  • Este es un gran comienzo… pero vale la pena señalar que esto imprime la expansión de la macro… no el valor. Si tiene una macro que se expande recursivamente a matemáticas largas (pero simples), posiblemente en términos de otras macros, es probable que esto no le ayude mucho.

    – Leopardo

    29 de julio de 2016 a las 13:34

  • Sería bueno si #pragma message permitido generar advertencias. #pragma GCC diagnostic warning "message " no lo permite (gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html).

    – pevik

    04/01/2018 a las 20:12

Si realmente desea emitir una advertencia, lo siguiente también funcionará. Sin embargo, depende de que C99 esté habilitado (funciona con gcc 4.8.2 o posterior, no probado en versiones anteriores):

#define N 77

#define __STRINGIFY(TEXT) #TEXT
#define __WARNING(TEXT) __STRINGIFY(GCC warning TEXT)
#define WARNING(VALUE) __WARNING(__STRINGIFY(N = VALUE))

#if N == 77
_Pragma (WARNING(N))
#endif

No recomendaría usar #advertencia, ya que no es C estándar. Además, ¿qué es lo que desea advertir pero no arrojar un error? Las advertencias suelen ser algo que el compilador usa cuando está haciendo algo que es sospechoso o completamente peligroso, pero permitido por el estándar C. No tiene tal caso en la aplicación normal, querrá que se compile sin problemas o que no se compile en absoluto. Por lo tanto, usaría #error estándar y no #advertencia no estándar.

No puede escribir el contenido real de la definición del preprocesador. Algo como esto podría ser suficiente:

#if (AAA < SOMETHING) && (AAA > SOMETHING_ELSE)
  #error AAA is bad.
#endif

Creo que esto es lo suficientemente detallado para el programador. Sin embargo, si usted De Verdad quiere más detalles y tiene un compilador de C moderno, puede usar afirmación_estática. Entonces puedes lograr algo cercano a lo que quieres:

#include <assert.h>

#define xstr(s) str(s)
#define str(s) #s
#define err_msg(x) #x " is " xstr(x)

#define AAA 17

static_assert(AAA != 17, err_msg(AAA));

este lío de macros debería imprimir AAA es 17. Se puede encontrar una explicación sobre cómo funcionan estas macros aquí.

No estoy seguro de si static_assert se incluyó en C99 o C11, ciertamente está en C11. Es posible que deba usar alguna extensión GCC para habilitarlo.

  • vea también esta pregunta para afirmaciones estáticas en C

    – mooooooooooooooooooooooo

    28 de septiembre de 2012 a las 11:46

  • Solo necesitaba un mensaje informativo con el valor de confirmar mi sospecha de que un parámetro interno global era incorrecto para un caso particular. No hay valores “malos” aquí. Resultó que era incorrecto. Pero gracias por static_assert, funciona desde g++ versión 4.3 con la opción -std=c++0x, y gcc versión 4.6 tiene static_assert con alias _Static_assert sin la opción.

    – elomage

    29 de septiembre de 2012 a las 13:25


  • @elomage _Static_assert es en realidad una palabra clave en C ahora, desde C11. contiene una macro static_assert, que se expande a _Static_assert. Cualquier forma debería estar bien para usar ya que ambos son estándar.

    – Lundin

    29/09/2012 a las 18:45

  • “¿Por qué…?” Porque si estoy cambiando algo en las bibliotecas de soporte central de la MCU que estoy usando, con fines de depuración (como redefinir el HAL_SYSTEM_RESET() macro de un registro de control real escriba en “while(1)” para que pueda inspeccionar el estado con un depurador), entonces quiero la seguridad de que dicha compilación nunca llega a un entorno en vivo. Todavía necesito que se construya para que la prueba funcione. Por supuesto, solo funciona si ejecuta una política de no advertencias en una compilación de producción…

    – Jostikas

    8 de julio de 2021 a las 7:28

  • El control de versión de @Jostikas es realmente útil y la solución correcta al problema que describe. Simplemente descargue su código modificado en una rama utilizada para la experimentación.

    – Lundin

    8 de julio de 2021 a las 7:34

avatar de usuario
gilberto

Muchas veces hago que mi Makefile genere un archivo generado localmente que contiene las definiciones deseadas.

generated.h:  Makefile
        echo >generated.h "// WARNING: generated file. Change Makefile instead"
        date >>generated.h '+//   generated on %Y-%m-%d %H:%M:%S'
        echo >>generated.h "#if AAA == AAA_bad"
        echo >>generated.h "#warning \"AAA = $(AAA_bad)\""
        echo >>generated.h "#endif"

La necesidad de #include “generated.h” es obvia.

Naturalmente, puede girar cualquier complejidad aquí, pero si se trata de más de unas pocas líneas, es posible que desee poner la complejidad en una secuencia de comandos separada, ya que los Makefiles desordenados pueden ser un problema de mantenimiento horrible. Con un poco de imaginación, puede tener bucles que generen una gran cantidad de pruebas a partir de una pequeña entrada.

Hacer que el destino generado.h dependa de Makefile es fundamental para garantizar que se vuelva a crear el archivo generado si las instrucciones en el destino cambian. Si tiene una secuencia de comandos generada.sh separada, también estaría en la lista de dependencias.

Descargo de responsabilidad: no he probado de verdad.

Otro método simple es, especialmente cuando se trata de un proyecto Makefile (como linux, u-boot, qemu, ..), puede ver el resultado preprocesado del archivo.
Por ejemplo,

para ver el archivo preprocesado de arch/arm64/kernel/head.S,
puedes hacer hacer arch/arm64/kernel/head.s. (s pequeña).

para ver el archivo preprocesado de foo/bar/baz.c,
puedes hacer hacer foo/bar/baz.i

Todas las macros se expanden al valor final.

¿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