2010-11-08 11 views
11

Duplicar posible:
Can I redefine a C++ macro then define it back?preprocesador Preservar definiciones

Decir que tengo un código que utiliza el nombre BLAH para una variable. Supongamos que BLAH es una definición de preprocesador común en muchos archivos de encabezado estándar (definido como 10), por lo que si mi archivo se incluye después de cualquiera de ellos, el código se rompe porque BLAH se transforma en 10; por lo tanto, debo #undef BLAH. Pero también otros encabezados pueden depender de BLAH, entonces debo restaurar BLAH a su valor original después de que mi encabezado esté listo. ¿Es posible hacer algo como esto:

#ifdef BLAH 
#define BLAH_OLD BLAH 
#undef BLAH 
#endif 

... code ... 

// restore BLAH to 10 
#ifdef BLAH_OLD 
#define BLAH BLAH_OLD 
#end 

? Esto no funciona, por supuesto, porque bla no se amplía a 10. He intentado hacer algo como

#define EXPAND_AGAIN(x) x 
#define EXPAND(x) EXPAND_AGAIN(x) 
#define BLAH_OLD EXPAND(BLAH) 

pero que no funciona bien, ya que EXPAND se toma literalmente, y no expandida. Estoy usando MSVC 2008/2010, pero sería encantador si la solución funcionara en la mayoría de los otros compiladores también.

+3

¿ha considerado el cambio de su denominación variable? –

+0

Cambia el nombre de tu variable; terrible convención que tienes pasando allí si esto es un problema. ¿Y qué tal en lugar de "digamos" usted dice "aquí está el problema real que estoy tratando de resolver". – GManNickG

+1

Usted se da cuenta de que ha sido una convención desde casi el principio de los tiempos que los identificadores que son todos los límites están reservados para el uso del pre-procesador (para evitar cosas como esta). –

Respuesta

-3

Un truco que funciona para mí es usar una enumeración en la clase.

class foo 
{ 
public: 
    enum { blah = 10 } myenum; 
} 

a continuación, puedes utilizar

foo:blah 

cuando se necesita '10'.

Dado que es parte de la clase, otros usos de 'blah' no entrarán en conflicto y se guardará todo lo que se defiende y descifra.

+1

¿Qué? '#define blah 0', rompe tu código. – GManNickG

+0

-1 para consejos que generalmente no funcionan. Si "blah" ya está definido como una macro de preprocesador, la definición de enumeración probablemente estará sintácticamente mal formada. La única posibilidad de pasar es cuando "blah" se define como un identificador válido. Cheers, –

+0

reemplaza la macro con la enumeración y desaparecen todos los problemas relacionados con las macro colisiones. No arreglará 'empujando' un valor. – Jay

0

Yo solía creer que el mismo truco que trataste funciona, ya que solía usarlo yo mismo. Pero finalmente aprendí que en realidad no funciona en absoluto. La respuesta simple es NO, no puede guardar el valor actual de una definición, cambiarla y restaurar el valor anterior. El preprocesador simplemente no funciona de esa manera. Una vez que define un nuevo valor, el valor anterior se ha ido.

19

Sí, dado que su compilador compatible con las directivas macro push/pop (Visual C++, GCC, llvm todos lo hacen):

#define BLAH 10 

#pragma push_macro("BLAH") 
#undef BLAH 

#define BLAH 5 

... 

#pragma pop_macro("BLAH") 
+0

Esto parece ser específico del compilador de Microsoft. –

+0

Lo sentimos, C++ estándar no define 'push_macro' (Visual C++ tiene este #pragma, pero no es C++ estándar). Cheers, –

+0

Al menos algunas versiones de GCC también lo admiten. –

4

Desafortunadamente el preprocesador no es compatible con una pila de definiciones.

La biblioteca del preprocesador Boost hace que el preprocesador haga cosas que nunca imaginaría que podría hacer (como efectivamente macros variadic en C++ 98), pero está sujeto a las limitaciones inherentes del preprocesador, por lo tanto, no se puede hacer , lo siento.

El único remedio intermedio conocido es reservar ALL_UPPERCASE_IDENTIFIERS para macros, y siempre utilícelas para macros. Reduce algo el problema de colisión de nombres. Lamentablemente, la biblioteca estándar de C define varias macros en minúsculas o permite su existencia, como p. Ej. assert, pero son solo algunas.

Desde un punto de vista práctico, el principal problema está en la programación de Windows, donde Microsoft [Windows.h] el encabezado define trillizos de macros que no son mayúsculas, incluidos, de forma predeterminada, min y max que entran en conflicto con la biblioteca estándar de C++.

Por lo tanto, para la programación de Windows C++, siempre defina NOMINMAX antes de incluir [windows.h].

Saludos & HTH.,

+0

gracias por 'NOMINMAX', pero hay' #pragma push_macro' al menos – Sergei

+0

@Sergei: Sí, '#pragma push_macro' es [la solución aceptada en la pregunta duplicada] (http://stackoverflow.com/a/1794089/464581). Pero como noté en un comentario sobre otra respuesta para esta pregunta, no fue estándar en 2010. Creo que todavía no es estándar, aunque está respaldado por, al menos, Visual C++, g ++ y clang. –