2012-09-28 55 views
29

Me gustaría imprimir un valor de macro (expandir la macro) en la directiva #warning.Preprocesador C: expandir macro en una advertencia #

Por ejemplo, para el código:

#define AAA 17 
#warning AAA = ??? 

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

warning: AAA = 17 

¿Qué puedo usar para ???, o, ¿cómo aumentar el código ?

+1

De acuerdo con el estándar de C a partir de 1999, es suficiente con '# error' para algo así y no expande ninguna macro, solo imprime el texto literalmente y hace que la compilación se detenga. ¿Qué intentas lograr con esto de todos modos? –

+0

Tengo una jerarquía de muchos archivos MAK que definen AAA de varias maneras, dependiendo de los parámetros del objetivo de creación. Me gustaría verificar que la definición sea correcta para el objetivo. Y no me gustaría crear una lista de #if AAA = 1 ... #warning "es 1" ... – elomage

+0

Además, esto es para el mundo integrado sin pantallas, por lo que no puedo probar fácilmente el valor de macro agregando algo como printf (#AAA); y verifíquelo en tiempo de ejecución. – elomage

Respuesta

37

Puede usar la directiva de 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 tener este aspecto:

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

para la referencia:

+0

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

+0

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

+2

asegúrese de usar '#pragma message' en lugar de' # message' o '# warning' – fantastory

2

Muchas veces tengo mi Makefile generar un archivo local generated.h 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 usted puede hacer girar cualquier complejidad aquí, pero si se pone más de unas pocas líneas es posible que quiere poner la complejidad en una secuencia de comandos independiente como Makefile desordenados pueden ser un problema de mantenimiento horrible. Con un poco de Imaginación puedes tener bucles que generan grandes cantidades de pruebas a partir de una pequeña entrada.

Hacer que el objetivo generated.h dependa de Makefile es fundamental para garantizar que se haya generado.h se rehace si cambian las instrucciones en el objetivo. Si tiene un script generado.sh separado, eso también estaría en la lista de dependencias.

Descargo de responsabilidad: no he probado de verdad.

7

no recomendaría el uso de #warning, ya que no es estándar C. Además, ¿qué es lo que desea advertir contra pero no generará un error en contra? Las advertencias son típicamente algo que el compilador usa cuando estás haciendo algo que es sospechoso, nuestro peligro absoluto, pero permitido por el estándar C. No tiene ese caso en la aplicación normal, va a querer compilar sin problemas o no compilarlo. Por lo tanto, utilizaría #error estándar y no estándar # warning.

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 realmente quiere más detalles y tiene un compilador moderno de C, puede usar static_assert.A continuación, se puede lograr algo parecido a lo que quiere:

#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 macro debe imprimir AAA es 17. Una explicación sobre cómo estos macros obra se encuentra here.

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

+0

ver también [esta pregunta] (http://stackoverflow.com/q/3385515/1025391) para aserciones estáticas en C – moooeeeep

+0

Solo necesitaba un mensaje informativo con el valor para 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 la versión 4.3 de g ++ con la opción -std = C++ 0x, y la versión 4.6 de gcc tiene static_assert aliased a _Static_assert sin la opción. – elomage

+0

@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. Cualquiera de las formas debería estar bien para usar ya que ambas son estándar. – Lundin

7

Si realmente desea emitir una advertencia, lo siguiente también funcionará. Sin embargo, depende de C99 está habilitado (funciona con gcc 4.8.2 o posterior, no se ha 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 
Cuestiones relacionadas