2009-10-09 13 views
34

Por alguna razón necesito deshabilitar temporalmente algunas macros en un archivo de encabezado y el #undef MACRONAME hará que el código se compile pero no definirá la macro existente.¿Cómo desactivo temporalmente una expansión de macros en C/C++?

¿Hay alguna manera de desactivarlo?

Debo mencionar que no conoce realmente los valores de las macros y que estoy buscando una solución de compilación cruzada (debería funcionar al menos en GCC y MSVC).

+0

Supongo que tiene una razón convincente para haber terminado realmente en este macro desastre? No podría pensar en uno aquí ... – sbi

Respuesta

68

En MSVC puede usar push_macro pragma, GCC supports para compatibilidad con los compiladores de Microsoft Windows.

#pragma push_macro("MACRONAME") 
#undef MACRONAME 

// some actions 

#pragma pop_macro("MACRONAME") 
+14

Es bueno saber que existe, y tan buena respuesta, pero eso es horrible. – Novelocrat

+2

Esta es la razón por la cual las personas nos siguen diciendo cosas como * las macros son malvadas *. Tarde o temprano alguien creará una macro llamada 'nueva' que hace algo estúpido ... –

+1

@JohnLeidegren bien, ahora estamos a mitad de camino. [** Ejemplo de una macro "malvada" mal interpretada **] (http://stackoverflow.com/q/18167990/319204). – TheCodeArtist

27

Utilizando solo las funciones definidas por la norma C (C89, C99 o C11), el único mecanismo de "desactivación" es #undef.

El problema es que no hay un mecanismo de "volver a habilitar".


Como otros han señalado, si el archivo de cabecera que contiene las definiciones de macro está estructurado de manera que no contiene ningún declaraciones typedef o enum (estos no se pueden repetir; función y declaraciones de variables se pueden repetir), entonces Podría #undef la macro, hacer lo que necesita sin la macro en efecto, y luego volver a incluir el encabezado, posiblemente después de definir su protección contra la reincorporación.

Si las macros no están definidas en un encabezado, por supuesto, está bloqueado hasta que refactorice el código para que esté en un encabezado.

Otro truco está disponible: si las macros son macros funcionales y no macros similares a objetos.

#define nonsense(a, b) b /\= a 

int (nonsense)(int a, int b) 
{ 
    return (a > b) ? a : b; 
} 

La función nonsense() se define bien, a pesar de la macro inmediatamente antes de ella. Esto se debe a que una macro invocación, para una macro de tipo función, debe ir seguida de un paréntesis abierto (dar o recibir espacio en blanco, posiblemente incluyendo comentarios). En la línea de definición de función, el token después de 'sinsentido' es un paréntesis de cierre, por lo que no es una invocación de la macro nonsense.

Tenía la macro ha sido un macro-objeto como argumento menos, el truco no funcionaría:

#define nonsense min 

int (nonsense)(int a, int b) 
{ 
    // Think about it - what is the function really called? 
    return (a > b) ? a : b; 
} 

Este código define una función falsa que se llama min y no tiene sentido. Y no hay protección de la macro.

Esta es una de las razones por las cuales la norma tiene cuidado de definir qué espacios de nombres están reservados para 'La implementación'. La Implementación tiene permiso para definir macros para cualquier propósito que desee o necesite, de cualquier tipo (similar a una función u objeto) que desee o necesite, siempre que esos nombres estén reservados para la implementación. Si usted, como consumidor de los servicios de The Implementation, trata de usar o definir un nombre reservado para la implementación, debe tener en cuenta que su código probablemente se romperá tarde o temprano, y que será culpa suya, no culpa de The Implementation. Implementación.

+7

Votación hacia arriba para la solución '(sinsentido)'. ¡Increíble! –

1

Las macros provienen de algún archivo de encabezado, por lo que debe tener acceso a sus valores.A continuación, puede hacer algo como

#include <foo.h> // declares macro FOO 

// Do things with FOO 

#undef FOO 

// do things without FOO 

#include <foo.h> // reenable FOO 

Su cabecera debe ser diseñada a lo largo de estas líneas

#ifndef FOO 
#define FOO do_something(x,y) 
#endif 
+4

Asegúrese de que no tiene otras cosas que no son macros que está habilitando/deshabilitando en ese archivo de encabezado o de lo contrario habrá problemas con la redeclaración. –

+6

También asegúrese de que '' no incluya el mantra '#ifndef FOO_H_INCLUDED/#define FOO_H_INCLUDED/.../# endif' para proteger contra la reinclusión. –

+2

Volver a incluir archivos de encabezado es probable que cause otros problemas a menos que los archivos de encabezado estuvieran específicamente diseñados para usarse de esta manera. –

0

EDIT:

Usted puede pensar que es así de fácil:

#ifdef macro 
#define DISABLED_macro macro 
#undef macro 
#endif 

// do what you want with macro 

#ifdef DISABLED_macro 
#define macro DISABLED_macro 
#endif 

Pero no es (como el siguiente ejemplo de demostración es)!

#include <iostream> 
#include <limits> 

#include <windows.h> 

#ifdef max 
#define DISABLED_max max 
#undef max 
#endif 

int main() 
{ 
    std::cout << std::numeric_limits<unsigned long>::max() << std::endl; 

#ifdef DISABLED_max 
#define max DISABLED_max 
#endif 

    std::cout << max(15,3) << std::endl; // error C3861: "max": identifier not found 
    return 0; 
} 

Usando #undef en la macro y volver a incluir la cabecera original es también no es probable que trabajar, debido a los guardias de cabecera. Entonces, lo que queda es usar las directivas push_macro/pop_macro #pragma.

#pragma push_macro("MACRO") 
#undef MACRO 
// do what you want 
#pragma pop_macro("MACR") 
+0

me ganó por 40 segundos más o menos ... – KitsuneYMG

+1

¿Excepto que funciona? ¿No "restaura" la macro de modo que se expandirá en "macro" (que es lo que estoy viendo cuando agregue las partes faltantes)? ¿Puede ser un ejemplo de uso completo? – UncleBens

+1

Esto no funciona - ver mi comentario a kts. – Novelocrat

2

macros hacen mis rodillas van débiles, pero no la solución más universal sea para reestructurar su código para que no tendría que volver a activar la macro de nuevo en el mismo archivo de origen? ¿No sería posible extraer algún código en una función separada y un archivo fuente separado donde no se pueda descifrar la macro ofensiva?

+0

Lo sentimos, pero a veces no puede modificar el código para solucionar este problema. – sorin

+0

Supongo que, mirando las otras respuestas, la única manera de "volver a habilitar" las macros en el caso general es copiar su definición original. – UncleBens

Cuestiones relacionadas