2011-03-28 10 views
10

me gustaría escribir código en C algo como esto:El uso definido (macro) en el interior del C if

 
if(defined(MACRO)) 
    ... 
else 
    ... 

pero no pude encontrar ninguna manera de hacer esto en C, ya el operador de preprocesador definido (MACRO) funciona solo dentro de # if's. ¿Hay alguna forma de hacer esto?

Lo que realmente me gusta hacer es escribir:

ASSERT(UART, var >= 0);

donde

 
#define ASSERT(NAME, TEST) \ 
    do { \ 
    if (defined(NAME) && !(TEST)) \ 
     printf("Assert failed"); \ 
    } while(0) 

por lo tanto podría dar vuelta a las pruebas de ASSERT cuando se define una macro y si no se define, entonces el afirma no debe ser verificado. Si intenta hacer esto, entonces se obtiene:

implicit declaration of function `defined'

que es bastante comprensible, ya que el compilador GCC no encuentra el operador defined() preprocesador.

+1

posible duplicado de [macro dependiente macro] (http://stackoverflow.com/questions/4927976/macro-dependent-macro) – kennytm

Respuesta

2

¿Por qué no simplemente define ASSERT de manera diferente dependiendo de esa macro?

#ifdef MACRO 
#define ASSERT(NAME, TEST) \ 
    do { \ 
     printf("Assert failed"); \ 
    } while(0) 
#else 
#define ASSERT(NAME, TEST) {} 
#endif 

usando valores fijos del preprocesador en C condicionales deben evitarse - Asegúrese de que el compilador debe optimizar el código muerto, pero ¿por qué confían en que cuando se puede separar esencialmente el código C real?

EDIT:

Hay un lugar fea truco que implica macro argumento stringification que usted puede ser capaz de utilizar:

#include <string.h> 
#include <stdio.h> 

#define X 

#define ERROR_(NAME, TEXT) \ 
     if (strcmp("", #NAME) == 0) \ 
       printf("%s\n", TEXT) 
#define ERROR(n, t) ERROR_(n, t) 

int main() { 
    ERROR(X, "Error: X"); 
    ERROR(Y, "Error: Y"); 

    return 0; 
} 

Este salidas:

$ ./test 
Error: X 

Esencialmente se utiliza el hecho de que cuando un token de preprocesador es no definido como un cro, se expande a sí mismo. Cuando, por otro lado, es definido se expande a una cadena vacía, o su definición. A menos que una de sus macros tenga su propio nombre como definición, este truco debería funcionar.

Descargo de responsabilidad: ¡Utilice esto bajo su propio riesgo!

(... porque yo sin duda alguna no lo uso!)

EDIT 2:

La salida de montaje de gcc -O0 -S para el programa anterior es:

 .file "test.c" 
     .section  .rodata 
.LC0: 
     .string "Error: X" 
     .text 
.globl main 
     .type main, @function 
main: 
.LFB0: 
     .cfi_startproc 
     pushq %rbp 
     .cfi_def_cfa_offset 16 
     movq %rsp, %rbp 
     .cfi_offset 6, -16 
     .cfi_def_cfa_register 6 
     movl $.LC0, %edi 
     call puts 
     movl $0, %eax 
     leave 
     ret 
     .cfi_endproc 
.LFE0: 
     .size main, .-main 
     .ident "GCC: (GNU) 4.4.3" 
     .section  .note.GNU-stack,"",@progbits 

Incluso sin optimización, GCC reduce este programa a una sola llamada puts().Este programa produce exactamente la misma salida de montaje:

#include <stdio.h> 

int main() { 
    puts("Error: X"); 

    return 0; 
} 

Por lo tanto, usted es probablemente no va a tener ningún problema de rendimiento, dependiendo de su compilador y las optimizaciones ...

+0

no, que no es bueno. Siempre quiero definir ASSERT, pero si NAME no está definido, entonces no quiero hacer nada. Además, no quiero adjuntar todos los usos de ASSERT con un #ifdef –

+0

@Miklos Maroti: ¿Entonces la definición de NAME no es global, mientras que ASSERT es, y quiere que ASSERT funcione solo cuando se define NAME? – thkala

+0

Quiero escribir un código como este: ASSERT (UART, var> = 0); ASSERT (SPI, var == 0); Entonces, si definí UART, entonces todas las aserciones uart deberían estar activadas, si defino SPI, entonces todas las aserciones spi deberían estar activadas, y no quiero un número fijo predefinido de subsistemas, es decir, ASSERT_UART, ASSERT_SPI no es una buena solución . –

5

Ok, basado en el post anterior tengo esta idea, que parece funcionar:

 
#define DEFINEDX(NAME) ((#NAME)[0] == 0) 
#define DEFINED(NAME) DEFINEDX(NAME) 

esto comprobará si se ha definido NOMBRE y por lo tanto se expande a la cadena vacía con 0 en su primer carácter, o que no está definido en el que cas e no es la cadena vacía. Esto funciona con GCC, por lo que uno puede escribir

 
if(DEFINED(MACRO)) 
    ... 
+0

Tenga en cuenta, sin embargo, que esto usa declaraciones C y solo se expandirá en el precompilador. Según tengo entendido, el C-Compiler se da cuenta de que el resultado de la condición es estático y elimina el código no utilizado ... – Johanness

+1

Genial, pero solo funciona para macros vacías ... Eso es si #define M y, entonces DEFINIDO (M) devolverá 0 (probado con gcc 4.5.1) – John

11

Una macro por comex se expande a 1 si el argumento se define a 1. De lo contrario, se expande a 0:

#define is_set(macro) is_set_(macro) 
#define macrotest_1 , 
#define is_set_(value) is_set__(macrotest_##value) 
#define is_set__(comma) is_set___(comma 1, 0) 
#define is_set___(_, v, ...) v 

Usted puede usarlo como sigue:

if (is_set(MACRO)) { 
    /* Do something when MACRO is set */ 
} 
+1

Esto debe aceptarse como la respuesta – dashesy

+0

El enlace al que se hace referencia ya no funciona (más). Ese es el problema general con qestions y respuestas que dependen de enlaces externos sin al menos citar la parte relevante. Tenga en cuenta que esto va en contra de las reglas del sitio y de un motivo negativo de votación negativa. – Olaf

+1

@Olaf, el enlace funciona para mí. Parece un enlace válido al perfil del usuario en G +: 'https://plus.google.com/u/ {id}/{id}/posts' – gavv

Cuestiones relacionadas