2010-06-13 36 views
7

Avviso: questa è una domanda strana.Espansione macro condizionale

Ho alcune macro veramente utili che mi piace usare per semplificare alcune registrazioni. Ad esempio, posso fare Log(@"My message with arguments: %@, %@, %@", @"arg1", @"arg2", @"arg3") e questo verrà espanso in un richiamo di metodo più complesso che include cose come self, _cmd, __FILE__, __LINE__, ecc., In modo da poter facilmente tracciare dove vengono registrate le cose. Funziona alla grande

Ora mi piacerebbe espandere i miei macro non solo per lavorare con i metodi Objective-C, ma anche con le funzioni C generali. Il problema sono le porzioni self e _cmd presenti nell'espansione macro. Questi due parametri non esistono nelle funzioni C. Idealmente, mi piacerebbe essere in grado di utilizzare lo stesso set di macro all'interno delle funzioni C, ma sto incontrando problemi. Quando uso (ad esempio) la macro Log(), ricevo gli avvisi del compilatore su self e _cmd non dichiarati (che ha senso).

Il mio primo pensiero è stato quello di fare qualcosa di simile alla seguente (nel mio macro):

if (thisFunctionIsACFunction) { 
    DoLogging(nil, nil, format, ##__VA_ARGS__); 
} else { 
    DoLogging(self, _cmd, format, ##__VA_ARGS__); 
} 

Questo produce ancora avvisi del compilatore, dal momento che l'intera istruzione if() viene sostituito al posto della macro, con conseguente errori con le parole chiave self e _cmd (anche se non verranno mai eseguite durante l'esecuzione della funzione).

Il mio prossimo pensiero è stato quello di fare qualcosa di simile (nel mio macro):

if (thisFunctionIsACFunction) { 
    #define SELF nil 
    #define CMD nil 
} else { 
    #define SELF self 
    #define CMD _cmd 
} 
DoLogging(SELF, CMD, format, ##__VA_ARGS__); 

che non funziona, purtroppo. Ottengo "errore:" # "non è seguito da un parametro macro" sul mio primo #define.

Il mio altro pensiero è stato quello di creare un secondo set di macro, specificamente per l'uso nelle funzioni C. Questo puzza di cattivo odore di codice, e io in realtà non voglio farlo.

C'è qualche modo posso usare lo stesso insieme di macro all'interno di entrambi i metodi Objective-C e le funzioni C, e fare riferimento solo self e _cmd se la macro è in un metodo Objective-C?

modificare ulteriori informazioni:

thisFunctionIsACFunction è determinato in un modo piuttosto rudimentale (e io sono assolutamente aperto a miglioramenti e suggerimenti). In sostanza è questo:

BOOL thisFunctionIsACFunction == (__PRETTY_FUNCTION__[0] != '-' && __PRETTY_FUNCTION__[0] != '+'); 

E 'basandosi sul comportamento del compilatore di aggiungere in testa un '-' o '+' per esempio, e di classe metodi su oggetti Objective-C. Qualsiasi altra cosa deve essere una funzione C (poiché le funzioni C non possono avere nomi che iniziano con '-' o '+').

Capisco che questo controllo è tecnicamente un controllo di runtime, dal momento che __PRETTY_FUNCTION__ viene sostituito con uno char*, e questo è probabilmente il maggiore ostacolo alla mia richiesta di aiuto.

+0

Come si arriva con 'thisFunctionIsACFunction'? – Artelius

+0

@Artelius ha modificato la domanda con ulteriori informazioni –

risposta

7

Il preprocessore fa tutto il suo lavoro prima che il codice effettivo venga analizzato. Il preprocessore non può sapere se una funzione è C o obj-C perché viene eseguita prima dell'analisi del codice.

Per lo stesso motivo,

if (thisFunctionIsACFunction) { 
    #define SELF nil 
    #define CMD nil 
} else { 
    #define SELF self 
    #define CMD _cmd 
} 
DoLogging(SELF, CMD, format, ##__VA_ARGS__); 

non può funzionare - i #defines vengono elaborati prima della fase di compilazione.

Quindi, il codice stesso deve contenere un controllo "runtime" (sebbene il compilatore possa ottimizzare questo out).

Vorrei suggerire che definisce qualcosa come

void *self = nil; //not sure about the types that 
SEL _cmd = nil; //would be valid for obj-c 

nell'ambito globale; le funzioni C "vedranno" queste definizioni mentre si spera che i metodi Objective-C li nascondano con le loro definizioni.

+0

+1 Ha! Sei un genio! Non avrei mai pensato di definire 'self' e' _cmd' a livello globale! Grazie! (E funziona perfettamente, l'ho appena provato). –

0

È possibile utilizzare una sorta di macro condizionale:

#ifndef OBJECTIVE_C 
    #define self 0 
    #define _cmd "" 
#endif 

Io non sono molto sicuro di quello che è necessario definire self e _cmd a, quelli erano solo supposizioni.

Non sono sicuro se esiste una macro predefinita che è possibile verificare se si sta compilando in Objective C, quindi potrebbe essere necessario definire OBJECTIVE_C manualmente come parte della build.

+0

Buona idea. L'unico problema è che Objective-C è un superset rigido di C, il che significa che ObjC e C possono coesistere pacificamente fianco a fianco. Ciò significa che la maggior parte delle mie funzioni C avrà '__OBJC__' # define'd. –

1

È possibile utilizzare

if defined "abc" <statement1> 
else if defined "def" <statement2>