2013-04-24 21 views
5

Stavo cercando una macro che assomigli al con-costrutto. L'utilizzo dovrebbe essere qualcosa di simile:"con" macro in C

with (lock(&x), unlock(&x)) { 
    ... 
} 

Potrebbe essere utile per altri scopi.

mi si avvicinò con questa macro:

#define __with(_onenter, _onexit, v) \ 
    for (int __with_uniq##v=1; __with_uniq##v > 0;)\ 
     for (_onenter; __with_uniq##v > 0; _onexit) \ 
      while (__with_uniq##v-- > 0) 

#define _with(x, y, z) __with(x, y, z) 
#define with(_onenter, _onexit) _with(_onenter, _onexit, __COUNTER__) 

Ha 3 cicli annidati perché dovrebbe:

  1. Inizializza contatore di ciclo (solo C99, ovviamente)
  2. Possibilmente inizializzare _onenter variabile (ad esempio with (int fd=open(..), close(fd)))
  3. Consentire break all'interno del blocco di codice. (continue è consentito anche. E la macro potrebbe essere regolata per assert() fuori)

ho usato sul codice per il sistema operativo XV6 e mi sembra molto utile.

La mia domanda è: quali sono i problemi peggiori con una tale macro? Voglio dire, oltre al semplice uso di una macro C (specialmente quella che implementa il nuovo costrutto del flusso di controllo).

finora hanno trovato questi inconvenienti/problemi:

  1. Nessun supporto per return o goto (ma si può risparmiare un po 'goto s in codice del kernel)
  2. Nessun supporto per gli errori (come fd < 0). Penso che questo sia risolvibile.
  3. gnu89/c99 e solo sopra (contatore loop. Non è necessario il trucco variabile univoco)
  4. Un po 'meno efficiente del semplice blocco-sblocco. Credo che sia insignificante.

Ci sono altri problemi? C'è un modo migliore per implementare un costrutto simile in C?

risposta

6

Questa macro mi spaventa. Preferirei lo traditional approach using gotos.

Questo approccio è primitivo, ma la maggior parte dei programmatori C conosce il modello e, se non lo sono, può capirlo leggendo il codice locale. Non c'è un comportamento nascosto. Di conseguenza, è abbastanza affidabile.

La tua macro è intelligente, ma sarebbe nuova per tutti e viene fornita con trucchi nascosti. Nuovi contributori dovrebbero essere considerati regole come "non return o goto su un blocco con" e "break uscirà dal blocco con, non dal circuito circostante". Temo che gli errori siano comuni

Il saldo si sposta se è possibile aggiungere avvisi al compilatore per gli abusi di questo costrutto. With clang, che sembra essere un'opzione. In questo caso, verrebbero rilevati abusi e il tuo codice resterebbe portatile ad altri compilatori.

Se si è disposti a limitarsi a GCC e Clang, è possibile utilizzare l'attributo cleanup.Ciò renderebbe il vostro esempio simile a questa:

lock_t x = NULL __attribute__((cleanup(unlock))); 
lock(&x); 

E unlock sarà chiamato con un puntatore alla variabile quando va fuori di portata. Questo è integrato con altre funzionalità linguistiche come return e goto e anche con eccezioni in progetti misti C/C++.

+0

Oh. risposta alla fine ... Grazie, non sapevo di "pulizia" - sembra utile. La macro ha problemi più specifici, oltre alla sua scarsità? – Elazar

+1

La mancanza di supporto per 'return' sembra un rompicapo, a meno che non si stia lavorando con uno standard di codifica rigoroso contro le istruzioni return in mezzo alle funzioni. Un 'return' in un blocco' with' apparirebbe poco appariscente ma causerebbe il caos in fase di esecuzione. – pdw

+0

Capisco e sono d'accordo sul fatto che 'return' è un grosso problema (quindi' cleanup' è molto meglio). Ma 'goto' non richiede uno standard di codifica altrettanto rigoroso? Quali sono i vantaggi di goto, in questo senso? – Elazar