2011-10-28 12 views
6

Sono sicuro che otterrò 20 persone che dicono "perché vorresti farlo comunque" ... ma, in ogni caso, farò la mia domanda perché è in qualche modo accademico.Utilizzo di macro C per creare un codice in stile C che mappa le chiamate ai messaggi Objective-C?

Vorrei utilizzare le macro C per ridefinire [ClassName new] in qualcosa come: new(ClassName) e mi chiedo come farlo. Non mi sento molto a mio agio con i macro C per cominciare (lo so - imbarazzante - dovrei esserlo) - e non sono assolutamente a mio agio nel mescolarli con il mio codice Objective-C. Così, con la domanda ...

In primo luogo, essendo è una cosa preprocessore, posso fare una semplice sostituzione, come ad esempio:

#define new(x) [x new] 

o, per qualsiasi motivo, ho bisogno di scendere fino a l'Objective-C runtime, e fare qualcosa di più simile a:

#define new(x) objc_msgSend(class_createInstance(x, 0), sel_registerName("init")) 

Quali sono le cadute di fare qualcosa di simile?

Questo tipo di cose viene usato spesso da altri, oppure qualcuno lo guarda e dice "che diavolo ci fai lì"? (E dovrei preoccuparmi)

Grazie

EDIT:

Mi venne in mente dopo questo distacco, che ho, infatti, vedere questo tipo di cose prima - nella cartella lib Three20, dove fanno cose del genere:

#define TT_RELEASE_SAFELY(__POINTER) { [__POINTER release]; __POINTER = nil; } 
#define TT_INVALIDATE_TIMER(__TIMER) { [__TIMER invalidate]; __TIMER = nil; } 

// Release a CoreFoundation object safely. 
#define TT_RELEASE_CF_SAFELY(__REF) { if (nil != (__REF)) { CFRelease(__REF); __REF = nil; } } 

Quindi probabilmente la mia domanda diventa semplicemente; Quali sono le carenze di questo, ed è una pratica relativamente accettata, o qualcosa che mi farà entrare più problemi di quanto valga la pena?

+0

Riguardo a come verrebbe ricevuto ... beh, i programmatori C [non mi piace '#define begin {'] (http://stackoverflow.com/questions/652788/what-is-the-worst-real -world-macros-pre-processor-abuse-youve-ever-come-across/652820 # 652820) (e ci sono altri esempi in quel thread), quindi probabilmente non piacerà neanche a questo. E ho simpatia. – delnan

+0

@delnan - Grazie per il link! Mi sento come se il mio esempio specifico fosse più in linea con l'intento dei macro di alcuni degli esempi citati in quel thread ... e ho visto macro usate in questo modo per il rilascio (vedi Three20 che usa quel 'pazzo TT_RELEASE_SAFELY' o qualunque cosa si chiami). – Steve

risposta

3

Le macro vengono elaborate per prime e funzionano con il codice sorgente del testo normale. Quindi sì, puoi avere la tua macro new generare la sintassi Objective-C o la sintassi C semplice o anche la sintassi non valida se lo desideri.

Le cadute dell'utilizzo di una macro in generale è che, poiché viene analizzata ed elaborata in un passaggio separato, è possibile scrivere macro che non si comportano come ci si aspetta anche quando tutto sembra a posto.

Per esempio, questa macro:

#define MAX(x,y) x > y ? x : y 

sembra ok, ma dire che hai usato in questo modo:

z = MAX(a,MAX(b,c)); 

Sarebbe essere espansa dal preprocessore in qualcosa di simile a questo:

z = a > b > c ? b : c ? a : b > c ? b : c; 

Quale non fornirà effettivamente il massimo dei tre argomenti. Per risolvere questo problema è necessario cospargere generosamente parentesi nella definizione macro, anche dove non ci si pensa è necessario:

#define MAX(x,y) ((x) > (y) ? (x) : (y)); 

che la fissa, tranne che ho aggiunto un punto e virgola alla fine, che è un'abitudine comprensibile dalla scrittura di un sacco di codice C, tranne che ora la nostra macro si espande a:

z = ((a) > (((b) > (c) ? (b) : (c));) ? (a) : (((b) > (c) ? (b) : (c));));; 

Errore di sintassi!

Se si guarda come lo MAX è effettivamente definito in Objective-C, è un bel caos, ma è quello che devi fare per scrivere in modo sicuro le macro. Ed è anche necessario considerare che:

z = MAX(expensiveComputation(), reallyExpensiveComputation()) 

Will, a differenza di una funzione, in realtà eseguire una di quelle funzioni due volte, a meno che non si utilizza un trucco nella macro per emulare fondamentalmente passaggio di parametri.

Quindi, per rispondere alla tua domanda, sì, è totalmente possibile, ma la scrittura di macro sicuri è davvero difficile. E lo stai facendo in modo che tu possa fingere che il tuo codice Objective-C sia in realtà un codice in un'altra lingua ... Perché dovresti farlo comunque?

+0

Punti fantastici ... Lo apprezzo davvero. Grazie. Qualche razionale eccellente. – Steve

3

macro C sono garantiti

  • di non essere ricorsiva
  • di non espandere le macro functionlike che non sono seguite da ()

così la vostra prima variante sarebbe ok per il preprocessore C. Gli unici identificativi che sono riservati (quindi non è possibile utilizzare per i nomi macro) sono le parole chiave e gli identificatori che iniziano con il carattere di sottolineatura. new non è una parola chiave (per C) né inizia con un carattere di sottolineatura, quindi questo va bene per il preprocessore C.

Non so se l'obiettivo-C impone altre restrizioni, dovresti cercare di farlo.

E sì, sono definitivamente il ragazzo che chiede "perché vorresti farlo comunque?". Non farlo, non pensare nemmeno a farlo, se d'altra parte senti il ​​bisogno di fare la tua domanda.

+0

Grazie! Questo è il tipo di cosa che sto cercando. – Steve

1

Supponendo che si sta utilizzando un recente GCC (che è una versione 4.6), si potrebbe considerare la possibilità di un GCC plug, o preferibilmente un GCC MELTestensione, per un tale compito. MELT è un linguaggio di dominio di alto livello per estendere facilmente GCC.

Per esempio, il new macro sarebbe

#define new(X) _mybuiltin_new_(X) 

e quindi l'estensione MELT sarebbe aggiungere un nuovo GCC incorporato _mybuiltin_new_ che verrebbe trasformato in un po 'più semplice Gimple (la rappresentazione interna usata da GCC). Tuttavia, questo tipo di cose richiede un po 'di tempo (almeno una settimana, non ore) da sviluppare.

Problemi correlati