2016-04-19 20 views
11

Sto utilizzando gcc (in particolare avr-gcc).Come posso ottenere il preprocessore gcc per verificare se un'espressione valuta un valore o nulla?

Quindi questo è il mio dilemma:

Diciamo che ho questi definita da qualche parte:

#define THING_0_A 0 
#define THING_0_B 1 
#define THING_1_A 0 

Poi, in un secondo file ho questo:

#define CONCAT_(A,B,C) A ## B ## C 
#define CONCAT(A,B,C) CONCAT_(A,B,C) 

#define ID 0 

#define THING_N(A) CONCAT(THING_,ID,A) 

Con questo ora ho una selezione di espressioni (sempre nel secondo file):

THING_N(_A) // evaluates to 0 
THING_N(_B) // evaluates to 1 
THING_N(_C) // evaluates to... nothing? Or undefined? Or THING_0_C? 

Ora, quello che sto cercando di capire è come fare questo (anche ancora nel secondo file):

#ifdef THING_N(_A) 
    // Do something knowing that THING_N(_A) is defined (in this case THING_0_A) 
#endif 

Oppure:

#if THING_N(_A) 
    // Do something knowing that the value THING_N(_A) evaluates to is defined and not just "nothing" 
#endif 

Naturalmente nessuno di questi lavori, perché #ifdef non può prendere un'espressione come argomento (e comunque finirebbe come "#ifdef 0"), e THING_N (_A) restituisce 0 all'interno di #if.

In altre parole, sto cercando un modo per rendere il preprocessore valutare:

THING_N(_A) to true 
THING_N(_B) to true 
THING_N(_C) to false 
THING_N(_D) to false 
etc... 

per essere utilizzato in un condizionale.

+2

Sembra un tipico problema [XY] (http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – Lundin

+0

Hai perfettamente ragione, sembra un problema XY (e sono contento che tu l'abbia menzionato perché non avevo mai sentito questo nome prima), ma in questo caso la suddetta è la mia X. Se qualcuno può allenarsi a Y allora forse applicherò quella Y ad una X in futuro. (cioè sto chiedendo questo per divertimento, curiosità e il desiderio di capire meglio come funziona il preprocessore C.) – Henry

+0

Se non c'è uno scopo pratico della domanda, è sempre possibile aggiungere il tag "avvocato linguistico", che significa che sei interessato ai meccanismi del linguaggio piuttosto che cercare di risolvere un problema del mondo reale. – Lundin

risposta

0

Così, dopo aver fatto un po 'di ricerca e di sperimentazione I' Ho concluso che non c'è una soluzione alla mia domanda, e la ragione di ciò è in realtà abbastanza semplice.

Data la configurazione che ho nella mia domanda a questo è ciò che le espressioni vengono valutate per:

THING_N(_A) -> THING_0_A -> 0 
THING_N(_B) -> THING_0_B -> 1 
THING_N(_C) -> THING_0_C -> 0 (Not nothing, as I previously thought.) 

Il pezzo di informazioni che mi mancava in precedenza era che, secondo la norma C99, identificatori non definiti verranno convertiti in 0, non nulla, rendendo impossibile distinguere tra qualcosa di indefinito e qualcosa definito come 0.

Se lo standard c99 scelto per rendere gli identificatori non definiti non valesse nulla, proprio come lo #define FOO fa in modo che FOO non valuti nulla, allora la soluzione di atturri avrebbe funzionato.

Oh bene.

2

Prova questo:

#if (1-THING_N(_A)-1 != 2) 

Questo sarà true per ogni valore di THING_N(_A) (tranne che per il valore -2). Sarà false solo se THING_N(_A) non è definito o è definito vuoto.

Se c'è una possibilità che la macro può espandersi a -2, è possibile modificare la seconda 1 e gli altri 2 a letterali di vostra scelta in modo che l'idea di base detiene.

+0

Mi piace molto questa idea. Sfortunatamente non sembra funzionare per me. L'espressione che hai scritto è vera quando THING_N (_A) non è definita. Sto indovinando perché valuta '(1-THING_0_A-1! = 2)' invece di '(1- -1! = 2)' come previsto. – Henry

+0

E ho appena scoperto che lo standard c99 dice che gli identificatori indefiniti sono sostituiti con 0 (non nulla), che darebbe: '1-THING_0_A -1! = 2' ->' 1-0 -1! = 2' -> '0! = 2' ->' 1' (vero). Quindi questo lo spiega. – Henry

0

È possibile concatenare il valore con un valore noto, e controllare il risultato:

#define EMPTY_VAL_HELPER(VAL) VAL ## 1 
#define EMPTY_VAL(VAL)   EMPTY_VAL_HELPER(VAL) 

Ora si potrebbe fare:

#if defined(FOO) && (EMPTY_VAL(FOO) == 1) 
//FOO is defined, but empty 
#endif 

#if defined(FOO) && (EMPTY_VAL(FOO) != 1) 
//FOO is defined, and not empty 
#endif 
+0

Il condizionamento di '# ifdef' da parte sua funzionerebbe perfettamente se tutto quello che volevo controllare fosse qualcosa come' #ifdef THING_0_A', ma non è quello che la mia domanda sta ponendo. Ciò di cui sono davvero curioso è il caso in cui si dispone di una macro e si desidera verificare se la cosa a cui la macro valuta è definita o meno. per esempio. '#ifdef THING_N (_A)' dove 'THING_N (_A)' valuta a 'THING_0_A' (che è definito), e' #ifdef THING_N (_C) 'dove' THING_N (_C) 'valuta a' THING_0_C' (che è non definito). – Henry