2010-06-11 15 views
20

Parece que a menudo paso demasiado tiempo tratando de obtener una macro #define para hacer exactamente lo que quiero. Voy a publicar mi dilema actual a continuación y cualquier ayuda es apreciada. Pero, realmente, la pregunta más importante es si hay alguna utilidad que alguien pueda recomendar, para mostrar rápidamente qué está haciendo realmente una macro. Parece que incluso el lento proceso de prueba y error iría mucho más rápido si pudiera ver lo que está mal.Cualquier utilidad para probar expandir C/C++ #define macros?

Actualmente, estoy cargando dinámicamente una larga lista de funciones desde una DLL que hice. La forma en que configuré las cosas, los punteros de función tienen los mismos números que las funciones exportadas, y los typedef (s) que se usaron para prototipos tienen los mismos nombres, pero con un guión bajo anexado. Por lo tanto, quiero usar una definición para simplificar las asignaciones de una larga lista de indicadores de función.

Por ejemplo, en la siguiente declaración de código, 'hexdump' es el nombre de un punto de función typedef'd, y también es el nombre de la función, mientras que _hexdump es el nombre de typedef. Si GetProcAddress() falla, un contador de fallas en incrementado.

if (!(hexdump = (_hexdump)GetProcAddress(h, "hexdump"))) --iFail; 

Así que digamos que me gustaría reemplazar cada línea como el de arriba con una macro, así ...

GETADDR_FOR(hexdump) 

Bueno este es el mejor que he encontrado hasta el momento . No funciona (mi comentario // es sólo para impedir que el formato de texto en el mensaje) ...

// #define GETADDR_FOR(a) if (!(a = (#_#a)GetProcAddress(h, "/""#a"/""))) --iFail; 

Y de nuevo, mientras yo le agradecería una idea de lo tonto error que he hecho, se Haría que mi día tuviera una utilidad que me mostraría el error de mis caminos, simplemente conectando mi macro.

+0

lo que el editor es u que utiliza? – Anycorn

Respuesta

19

Usted sólo puede ejecutar el código a través del preprocesador, que le mostrará lo que se ampliará en (o escupir errores como sea necesario):

 
$ cat a.c 
#define GETADDR_FOR(a) if (!(a = (#_#a)GetProcAddress(h, "/""#a"/""))) 
GETADDR_FOR(hexdump) 

$ gcc -E a.c 
# 1 "a.c" 
# 1 "<built-in>" 
# 1 "<command-line>" 
# 1 "a.c" 
a.c:1:36: error: '#' is not followed by a macro parameter 

GETADDR_FOR(hexdump) 

En GCC, es gcc -E foo.c sólo puede procesar previamente el archivo .

Visual Studio uses argumento /P.

+0

Gracias. Creo que investigaré en GCC. Supongo que estaba esperando algo que simplemente hiciera una "expansión lo mejor que pueda" en mi macro para poder ver lo que hacía visualmente. Pero supongo que al igual que el código C erróneo, si mi macro es basura total, el pre-procesador probablemente no podría expandirlo en absoluto. ;-). Supongo que solo necesito leer una mejor documentación sobre el tema. Pero aún así sería bueno tener algo que arrojó el resultado de una expansión exitosa, porque lo que es mucho peor que un mensaje de error, es una expansión que funciona, ¡pero que no genera el código esperado! ¿Lo hará GCC/P? – Randy

+1

@Randy: En realidad, Boost Wave, que Jerry Ataúd recomendable, tiene una función de "reemplazo de trace" donde se da salida a un archivo que muestra los pasos que tomó durante la sustitución de macro. Es muy detallado, porque a menudo hay muchos más pasos de los que normalmente pensamos, pero puede ser muy útil, especialmente para definiciones macro complejas o largas. –

+0

@Randy: Soy de la opinión de que si su macro es lo suficientemente complicada como para necesitar una sofisticada herramienta de depuración, está haciendo algo mal. :-) – Omnifarious

1

Es posible que desee echar un vistazo a Boost Wave. Como la mayoría de Boost, en realidad es más una biblioteca que una utilidad, pero tiene un controlador para actuar como un preprocesador completo.

+0

No sé por qué esto se downvoted ... Wave tiene una aplicación preprocesador (sin embargo, no es del todo completa, hay varios aspectos oscuros de la sustitución de macro que no es compatible). –

+0

@ James: Sí, "completa" fue probablemente la palabra equivocada - Yo sólo quería decir que no tiene código de controlador para que pueda compilar y vincular como un programa completo, ejecutable. Si (por ejemplo) desea la sustitución de macros * sin * inclusión de archivos, se trata del mejor punto de partida que conozco (y usted * con frecuencia * no desea la inclusión de archivos, ya que puede/producirá mucho volumen para escanear a través de encontrar lo que te importa). –

2

Parece ser que está confundido acerca de cuál es la sintaxis exacta para la codificación o la pegada de tokens en las macros de preprocesador de C.

Puede que usted encuentre útil esta página acerca de C preprocessor macros in general.

En particular, creo que esta macro debe leer como esto:

#define GETADDR_FOR(a) if (!(a = (_##a)GetProcAddress(h, #a))) --iFail 

El trailing ; debe omitir porque es probable que se escribiendo esto como GETADDR_FOR(hexdump);, y si no lo hace se verá muy extraño en su código C y confunde muchos marcadores de sintaxis.

Y como alguien más mencionó gcc -E ejecutará el preprocesador y omitirá los otros pasos de compilación. Esto es útil para depurar problemas del preprocesador.

+0

¡Ah, gracias! Ciertamente tenía un concepto pobre del uso correcto del corrector #. ¡Pero es uso y uso de la concatenación! ¡Muy apreciado! Y gracias por el enlace del artículo. ¡Parece mucho más completo que las notas breif que encontré en MSDN! – Randy

4

Va a https://godbolt.org/. Ingrese su código en el panel izquierdo y seleccione el compilador, ya que gcc coloca el argumento como -E en el panel derecho. Su código preprocesado aparecerá a la derecha.

Cuestiones relacionadas