2010-12-30 21 views
5

Tengo un código que tiene muchos códigos de error #define complicados que no son fáciles de descodificar ya que están anidados en varios niveles.¿Cómo puedo generar una lista de valores #define a partir del código C?

¿Hay alguna manera elegante en que pueda obtener una lista de #defines con sus valores numéricos finales (o lo que sea)?

A modo de ejemplo:

<header1.h> 
#define CREATE_ERROR_CODE(class, sc, code) ((class << 16) & (sc << 8) & code) 
#define EMI_MAX 16 

<header2.h> 
#define MI_1 EMI_MAX 

<header3.h> 
#define MODULE_ERROR_CLASS MI_1 
#define MODULE_ERROR_SUBCLASS 1 
#define ERROR_FOO CREATE_ERROR_CODE(MODULE_ERROR_CLASS, MODULE_ERROR_SUBCLASS, 1) 

me gustaría tener un gran número de #defines similares a juego ERROR _ [\ w _] + que me gustaría enumerar de manera que siempre tengo una lista de códigos de error que el programa puede producir. Necesito el valor numérico porque eso es todo lo que el programa imprimirá (y no, no es una opción imprimir una cadena en su lugar).

Las sugerencias para gcc o cualquier otro compilador serían útiles.

+0

¿Ha considerado ** usar constantes reales ** en lugar de #defines? –

+0

Cambiar el código a constelaciones no sería práctico ya que se hereda de una fuente ascendente. – djs

Respuesta

4

Creo que la solución es un conjunto de respuestas de @nmichaels y @ aschepler.

Utilice la opción -dM de gcc para obtener una lista de las macros. Use perl o awk o lo que sea para crear 2 archivos de esta lista:

1) Macros.h, que contiene solo #defines.

2) Codes.c, que contiene

#include "Macros.h" 

ERROR_FOO = "ERROR_FOO" 
ERROR_BAR = "ERROR_BAR" 

(es decir: extraer cada #define ERROR_x en una línea con la macro y una cadena

ahora ejecutar gcc -E Codes.c Eso debería crear un archivo con todos.. las macros expandidas. El resultado debe ser algo así como

1 = "ERROR_FOO" 
2 = "ERROR_BAR" 

no tengo gcc a mano, por lo que no han probado este ...

+1

Intenté esto y con solo un 6 por ciento de líneas de procesamiento, ¡finalmente terminé con una lista ordenada de valores numéricos! Un problema con esta solución es gcc -E -P da un archivo masivo con todos los encabezados preprocesados. Quité -P y tomé solo las líneas después de "# 2 Codes.c 2". Soluciona esto y creo que ganas la recompensa ... – djs

+0

hecho. -P se suponía que debía "Inhibir la generación de linemarkers en la salida del preprocesador", lo que parecía útil para hacer que el archivo se viera más limpio. Oh bien. – AShelly

+0

El concepto clave que perdí aquí fue que no podía preprocesar el encabezado, necesitaba ejecutar un archivo C haciendo referencia a esas constantes para expandirlo realmente. La otra parte que extrañé me di cuenta: solo puedo llegar a una expresión aritmética, que necesito evaluar. Técnicamente, supongo que necesito compilarlo, pero lo engañé y lo pasé a Perl Eval. – djs

7

GCC -dMpreprocessor option puede obtener lo que desea.

+0

Parece una buena idea, pero no expande mis macros. He intentado ejecutar 'gcc -E-Wp, -dD header3.h y termino con exactamente el mismo #define como se define arriba. – djs

+1

@djs: Sí, no es del todo el camino. '-dM' arrojará una lista de macros que puede alimentar en un script para generar las expansiones. – nmichaels

+0

El resultado final es que tengo una lista de macros similares a funciones que el preprocesador puede expandir, pero que ciertamente no quiero hacer. Entonces necesito alguna forma de expandirlos ... – djs

1

Si usted tiene una lista completa de las macros que desea ver, y todos son numéricos, puede compilar y ejecutar un programa corto para este fin:

#include <header3.h> 
#include <stdio.h> 

#define SHOW(x) printf(#x " = %lld\n", (long long int) x) 

int main(void) { 
    SHOW(ERROR_FOO); 
    /*...*/ 
    return 0; 
} 

Como @nmichaels mencionan, gcc de -d las banderas pueden ayudar a obtener esa lista de macros para mostrar.

2

El programa 'coan' se parece a la herramienta que está buscando. Tiene el control secundario 'defs', que se describe como:

defs [Opción ...] [...] [archivo de directorio ...]

Seleccione #define y directivas de #undef los archivos de entrada de acuerdo con las opciones e informarlos en la salida estándar de acuerdo con las opciones.

Consulte la URL citada para obtener más información sobre las opciones. Obtenga el código here.

+0

Interesante aplicación. Estaba realmente emocionado hasta que descubrí que no es compatible con la expansión de macros similares a funciones. Hay un defecto abierto para solucionar esto, así que tal vez algún día será la respuesta. – djs

1

He aquí una pequeña solución creativa:

Escribir un programa para que coincida con todos sus identificadores con una expresión regular (como \#define :b+(?<NAME>[0-9_A-Za-z]+):b+(?<VALUE>[^(].+)$ en .NET), y luego tener que crear otro archivo C con sólo los nombres coincidentes:

void main() { 
    /*my_define_1*/ my_define_1; 
    /*my_define_2*/ my_define_2; 
    //... 
} 

Luego preprocesa el archivo con la opción/C/P (para VC++), y debe obtener todos esos valores reemplazados. Luego use otra expresión regular para cambiar las cosas, y coloque los comentarios antes de los valores en el formato #define - ¡ahora tiene la lista de #define!

(se puede hacer algo similar con GCC.)

0

¿Hay alguna manera elegante puedo obtener una lista de #defines con sus valores numéricos finales

Por diversos niveles de elegancia, tipo de

#!/bin/bash 

file="mount.c"; 
for macro in $(grep -Po '(?<=#define)\s+(\S+)' "$file"); do 
    echo -en "$macro: "; 
    echo -en '#include "'"$file"'"\n'"$macro\n" | \ 
    cpp -E -P -x c ${CPPFLAGS} - | tail -n1; 
done; 

no es infalible (#define \ \n macro(x) ... no entraría en el ámbito - pero hay un estilo que he visto hace que).

Cuestiones relacionadas