2012-01-23 12 views
7

partes de mi código dependen del valor de un símbolo de preprocesador:¿Hay manera de comprobar el tipo de un valor de símbolo de preprocesador en C/C++

int a() 
{ 
#if SDK_VERSION >= 3 
    return 1; 
#else 
    return 2; 
#endif 
} 

La comparación depende del valor de SDK_VERSION. Se espera que sea un entero o algo que se compare con un entero, en este caso, 3. Si SDK_VERSION es algo que no se puede comparar con un entero, habrá un error de compilación.

¿Hay alguna forma de cancelar la compilación si SDK_VERSION no es del tipo esperado? Por ejemplo:

#if type(SDK_VERSION) != int # Does not compile, I know 
#error "SDK_VERSION must be an integer." 
#endif 
+1

El mensaje de error sería un poco más oscuro, pero poner algo como 'int ___SDK_VERSION_SHOULD_BE_CONVERTIBLE_TO_INT___ = SDK_VERSION;' en el encabezado que incluye 'SDK' podría resolver su problema. –

+3

Usted dice que ya obtiene un error de compilación si 'SDK_VERSION' es del tipo incorrecto, ¿es lo que quiere un mensaje de error más agradable/diferente? – spatz

+0

@ FrédéricHamidi: Ignorando los problemas asociados con el doble guión bajo en sus identificadores. –

Respuesta

11

Usar plantilla para generar dicho error:

template<typename T> struct macro_error; 

template<> struct macro_error<int> {}; 

template<typename T> void check(T) 
{ 
    macro_error<T> SDK_VERSION_must_be_int; 
} 
int ignored = (check(SDK_VERSION), 0); 

Este código generaría error de compilación, que tiene la siguiente secuencia en que, si el SDK_VERSION no es de tipo int:

SDK_VERSION_must_be_int 

ver estas demostración:

Y también observar el mensaje de error en el primer caso. Imprime esto:

prog.cpp:9: error: ‘SDK_VERSION_must_be_int’ has incomplete type 
prog.cpp:9: warning: unused variable ‘SDK_VERSION_must_be_int’ 
+1

No aplicable a C. –

2

Esto no compila si SDK_VERSION es una cadena (pero funcionaría para un float ...):

int get_SDK_Version() 
{ 
    return SDK_VERSION; 
} 
4

Nop. La razón es que el símbolo del preprocesador no tiene ningún tipo.

Los símbolos de preprocesador se consideran mejor que apenas un poco más que una cadena. El sistema de tipos de C realmente no existe hasta el paso de compilación, que ocurre una vez que el preprocesador ha tenido éxito.

+0

Ooh, aunque me gusta la respuesta de Jason - listo , pero asegúrese de agregar cierta documentación, porque cuando falla la compilación, no está muy claro que la intención del fragmento era verificar el tipo de SDK_VERSION. – Matt

0

El preprocesador no tiene conocimiento de los tipos ni de ninguna de las palabras clave del idioma.

0

Estoy pensando que podría sacar algo de meta-programación de plantillas aquí.

Voy a intentar algo de magia y publicar un ejemplo si consigo algo que funcione. Mi teoría es que podrías instanciar una clase o plantilla de función. La definición predeterminada de la plantilla daría lugar a un error de compilación si no es del tipo apropiado. Sin embargo, una especialización de plantilla para int no generaría un error.

Esto está fuera del rango de mi experiencia con la magia de plantilla y preprocesador, pero vale la pena echarle un vistazo. Un problema que espero es que SDK_VERSION no sea más que un símbolo para ser sustituido. SDK_VERSION no tiene un tipo, per-se.

En el mejor de los casos, creo que se puede comprobar a qué tipos se puede convertir, pero el concepto de un preprocesador definido como "constante" es muy ... fuerza bruta, casi hackish. Puede ser una práctica común, pero no es para nada seguro. Lo mejor es recordar que son solo una versión de preprocesador de buscar y reemplazar.

0

De hecho, la directiva #if considera lo que está a su derecha como enteros.

Así que si quieres lograr lo que pediste, tienes que hacer algunos aritméticos. Por ejemplo hacer un archivo con test.c:

#define VERSION 7 

#if VERSION 
    #if VERSION - (VERSION % 10) 
    #warning Number out of range (1-9) 
    #else 
    #warning Number in range (1-9) 
    #endif 
#else 
    #warning Zero or not a number 
#endif 

compilar con

gcc -c -o /dev/null test.c 

Usted la recibe el mensaje: "Cero no es un número de" ... si su versión es 0, o no evalúa (en preprocesador) como un entero.

Y si VERSION se evalúa como un número entero, obtendrá el primer o segundo mensaje según su valor.

Esto le permitirá hacer lo que estaba buscando.

Documentación sobre #if: http://gcc.gnu.org/onlinedocs/cpp/If.html

Nota que entero se puede expresar como: 123 o 0xCC o cualquier cosa que se evalúa como una constante después de la expansión macro recursiva entero.

Si el número es un punto flotante como: 3.14 se considera cero.

No se puede simplemente distinguir 0 (el entero) con algo que no es un número entero. Sin embargo, probablemente exista la posibilidad de utilizar la concatenación de cadenas de macros, pero aún no se ha explorado.

Cuestiones relacionadas