2013-09-25 5 views
11

C'è un modo per scrivere una macro di preprocessore C che si espande in cose diverse a seconda dell'argomento che riceve?È possibile inserire un preprocessore condizionale all'interno di una macro C?

#define foo() ??? 

/* 1 */ 
foo(name) 

/* 2 */ 
foo(_) 

risultato desiderato:

/* 1 */ 
int name; 

/* 2 */ 
/*ignore*/ 

sì, lo so macro sono il male. Lo sto chiedendo principalmente per curiosità.

+12

I macro sono fantastici. –

+2

Puoi spiegare lo scopo, o forse dare un esempio migliore? Il parametro dovrebbe essere corretto in fase di compilazione, il che significa che potresti anche usare due diversi nomi di macro. – lurker

+0

@mbratch: In questo caso particolare, sto usando una macro per definire un insieme di variabili ma alcune variabili sono facoltative e voglio evitare di definirle. I nomi di macro multipli non funzionerebbero bene a causa di un'esplosione combinatoria: con due nomi variabili avrei bisogno di macro separate per 'foo (a, b)', 'foo (a, _)', 'foo (_, b)' e ' foo (_, _) '. – hugomg

risposta

8

Forse provare qualche espansione macro multistadio? Questa è la strategia utilizzata da Boost preprocessor/control/if library.

#define FOO_NAME 1 
#define FOO__ 2 

#define CONC(a,b) a##_##b 
#define FOO(x) CONC(FOO,x) 

Non penso ci sia alcun modo per verificare le condizioni all'interno di un'espansione macro C.

La cosa migliore che potrei inventare è di nascondere gli argomenti macro a una stringa letterale usando l'operatore di stringaggio # e quindi controllando l'utilizzo delle funzioni di runtime. (Questo non funziona per il vostro caso, però, in cui si desidera dichiarazioni di variabili di output.)

Per esempio, i seguenti stampe "011":

#define FOO(x) (strcmp("NAME", #x) ? 1 : 0) 

main() 
{ 
    printf("%d", FOO(NAME)); 
    printf("%d", FOO(1)); 
    printf("%d", FOO(2)); 
} 

Il compilatore probabilmente ottimizzare i strcmp confronti in fase di compilazione quindi non sarebbe più inefficiente di quanto sarebbe stato se fossero disponibili veri condizionali pre-processore. Tuttavia, rendendo FOO una funzione normale sarebbe più chiara e probabilmente altrettanto efficiente.

+0

Interessante trucco! Ma c'è un modo in cui non ho bisogno di enumerare tutte le possibilità per il caso "1"? Ad esempio, se il suo '_' allora la macro produce 2 se è qualcos'altro che produce 1? – hugomg

+0

Ho aggiornato la mia risposta con una soluzione alternativa che non funzionerà per la tua domanda originale. –

+0

Purtroppo, nel mio caso non posso utilizzare un test di runtime. Sto iniziando a pensare che la prima soluzione per te sia la migliore che otterrò. – hugomg

8

Ad ampliare la risposta di Gavin Smith, in realtà si può verificare le condizioni all'interno di una macro di espansione:

#define FOO_name 1 
#define FOO__ 0 

#define CONC(a,b) a##_##b 

#define IF(c, t, e) CONC(IF, c)(t, e) 
#define IF_0(t, e) e 
#define IF_1(t, e) t 

#define FOO(x) IF(CONC(FOO,x), int x;,) 

FOO(name) // -> int name; 
FOO(_) // -> /*nothing*/ 

Se vi sentite avventurosi si può facilmente estendere IF per consentire le virgole, sopprimere macro di espansione, ecc macro di supporto.

Come sopra, tuttavia, è necessario conoscere in anticipo tutti i nomi desiderati.

Problemi correlati