¿Cómo probar si el símbolo del preprocesador está # definido pero no tiene valor?

Al usar las directivas de preprocesador de C ++, ¿es posible probar si se ha definido un símbolo de preprocesador pero no tiene valor? Algo como eso:

#define MYVARIABLE #if !defined(MYVARIABLE) || #MYVARIABLE == "" ... blablabla ... #endif 

EDITAR: La razón por la que lo estoy haciendo es porque se supone que el proyecto en el que estoy trabajando toma una cadena del entorno a través de /DMYSTR=$(MYENVSTR) , y esta cadena podría estar vacía. Quiero asegurarme de que el proyecto no se compile si el usuario olvidó definir esta cadena.

Soma macro magic:

 #define DO_EXPAND(VAL) VAL ## 1 #define EXPAND(VAL) DO_EXPAND(VAL) #if !defined(MYVARIABLE) || (EXPAND(MYVARIABLE) == 1) Only here if MYVARIABLE is not defined OR MYVARIABLE is the empty string #endif 

Tenga en cuenta que si define MYVARIABLE en la línea de comandos, el valor predeterminado es 1

 g++ -DMYVARIABLE  

Aquí el valor de MYVARIABLE es 1

 g++ -DMYVARIABLE=  

Aquí el valor de MYVARIABLE es la cadena vacía

El problema de cotización resuelto:

 #define DO_QUOTE(X) #X #define QUOTE(X) DO_QUOTE(X) #define MY_QUOTED_VAR QUOTE(MYVARIABLE) std::string x = MY_QUOTED_VAR; std::string p = QUOTE(MYVARIABLE); 

Quiero asegurarme de que el proyecto no se compile si el usuario olvidó definir esta cadena.

Mientras revisaba esto en un paso de comstackción anterior, puedes hacerlo en tiempo de comstackción. Usando Boost por brevedad:

 #define A "a" #define B BOOST_STATIC_ASSERT(sizeof(BOOST_STRINGIZE(A)) > 1); // succeeds BOOST_STATIC_ASSERT(sizeof(BOOST_STRINGIZE(B)) > 1); // fails 

No he visto esta solución al problema, pero me sorprende que no sea de uso común. Parece funcionar en Xcode Objc. Distinguir entre “definido sin valor” y “conjunto definido 0”

 #define TRACE #if defined(TRACE) && (7-TRACE-7 == 14) #error TRACE is defined with no value #endif 

No creo que esto se pueda hacer. Dicho esto, no veo la necesidad de hacerlo. Cuando #define símbolo de #define preprocesador, debe establecer una convención que lo defina como 1 o 0 para usar en #if , o dejarlo en blanco.

Puede usar la macro BOOST_PP_IS_EMPTY la BOOST_PP_IS_EMPTY manera:

 #include  #define MYVARIABLE #if !defined(MYVARIABLE) || !BOOST_PP_IS_EMPTY(MYVARIABLE) // ... blablabla ... #endif 

Eso hizo el truco para mí. Agregaré que esta macro no está documentada, así que utilícela con precaución.

Fuente: preprocesador-faltante-IS-EMPTY-documentación

No se puede, ya que el preprocesador solo puede verificar un valor numérico. La comparación de cadenas no está cubierta por la syntax del preprocesador.

Para macros de solo enteros …

Puedes usar un hack sin macros extra:

 #if ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1 /* MYVARIBLE is undefined here */ #endif 

La respuesta de Mehrad debe ampliarse para que funcione. También su comentario

/ * MYVARI (A) BLE no está definido aquí * /

no es correcto; para probar una variable no definida, existe la prueba simple #ifndef MYVARIABLE .

Después de tal prueba, sin embargo, su expresión conduce a una solución correcta de la pregunta original. Probé que este código funciona, para valores no definidos, definidos pero vacíos y no vacíos de la macro MYVARIABLE:

 #ifndef MYVARIABLE /* MYVARIABLE is undefined here */ #elif ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1 /* MYVARIBLE is defined with no value here */ #else /* MYVARIBLE is defined here */ #endif 

La statement #elif ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1 funciona de la siguiente manera:

  • Cuando MYVARIABLE se define pero está vacío, se expande a ~(~+0) == 0 && ~(~+1) == 1 , que funciona 0==0 && 1==1 (la doble negación ~~ es una operador de identidad).
  • Cuando MYVARIABLE se define como un valor numérico, diga n, se expande a ~(~n+0)==0 && ~(~n+1)==1 . En el lado izquierdo de && , la expresión ~(~n+0)==0 evalúa como n==0 . Pero con n==0 , el lado derecho se evalúa como ~(~0+1)==1 , con ~ 0 siendo -1 a ~(-1+1)==1 , luego ~0==1 y finalmente -1==1 , que obviamente es falso.
  • Cuando MYVARIABLE se define como un valor no numérico, el precomstackdor reduce todos los símbolos desconocidos a 0, y obtenemos el caso anterior con n == 0 una vez más.

Mi código de prueba completo (guardar como archivo test.c):

 #include  int main() { printf("MYVARIABLE is " #ifndef MYVARIABLE "undefined" #elif ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1 "defined without a value" #else "defined with this value : %i", MYVARIABLE #endif ); printf("\n"); } 

Con el preprocesador GNU cpp puede experimentar para ver qué código se produce:

 # undefined cpp test.c #defined without a value cpp -DMYVARIALBE= test.c #defined wit an implicit value 1 cpp -DMYVARIALBE test.c #defined wit an explicit value 1 cpp -DMYVARIALBE=1 test.c #defined wit an explicit value a cpp -DMYVARIALBE=a test.c 

o salida de comstackción y ejecución (bajo algún linux)

 $ gcc -o test test.c ; ./test MYVARIABLE is undefined $ gcc -DMYVARIABLE= -o test test.c ; ./test MYVARIABLE is defined without a value $ gcc -DMYVARIABLE -o test test.c ; ./test MYVARIABLE is defined with this value : 1 $ gcc -DMYVARIABLE=1 -o test test.c ; ./test MYVARIABLE is defined with this value : 1 $ gcc -DMYVARIABLE=a -o test test.c ; ./test test.c: In function 'main': :0:12: error: 'a' undeclared (first use in this function) ... 

En la última ejecución, donde MYVARIABLE se define como ‘a’, el error no es un error en la definición de macro; la macro está correctamente dirigida al último caso, “definido con este valor …”. Pero este valor es ‘a’ y ‘a’ no se define en el código, el comstackdor o el curso tienen que señalar esto.

De esa manera, el último caso es un muy buen ejemplo de por qué la intención de la pregunta original es muy peligrosa: a través de una macro, el usuario puede introducir cualquier secuencia de líneas de progtwig en el código a comstackr. La comprobación de que dicho código no se ha introducido requiere una comprobación mucho mayor de la macro en valores válidos. Probablemente se necesita un script completo, en lugar de dejar esta tarea a preprocesamiento. Y en ese caso, ¿de qué sirve verificarlo también en el preprocesamiento?

#if MYVARIABLE==0 Mi respuesta debe ser de al menos 30 caracteres, ¡así que debería hacerlo!