2011-10-19 20 views
11

Recentemente ho trovato questa macro GCC:Come `({...})` restituisce un valore?

#define max(a,b) \ 
    ({ typeof (a) _a = (a); \ 
     typeof (b) _b = (b); \ 
    _a > _b ? _a : _b; }) 

Non avevo capito che prima di vedere questo codice, che un blocco di codice {...} possa in qualche modo il valore di ritorno in C.
1) Mi potrebbe dare un suggerire come funziona?

Benché, di solito è in grado di ottenere lo stesso risultato abusando l'operatore virgola:

#define max(a,b) \ 
    (typeof (a) _a = (a), \ 
    typeof (b) _b = (b), \ 
    (_a > _b ? _a : _b)) 

o se era solo per effetto collaterale userei do { ... } while(0)

2) Nei è il modo preferito per farlo?

+1

che potrebbe diventare una domanda protetta! molti programmatori C (e C++, credo) non sanno che '({...})' è un'estensione GCC e non fa parte del linguaggio C. A PARER MIO. – Jack

risposta

9

Il costrutto ({ ... }) è un'estensione gcc.

Così è l'operatore typeof.

A MAX macro (notare l'uso convenzionale di tutto in maiuscolo) è abbastanza facile da scrivere:

#define MAX(a, b) ((a) > (b) ? (a) : (b)) 

Non valutare uno dei suoi argomenti più di una volta, quindi non dovrebbe invocarlo come, ad esempio, MAX(x++, y--). L'uso di tutte le maiuscole serve a ricordare all'utente che si tratta di una macro, non di una funzione, e di fare attenzione agli argomenti con effetti collaterali.

Oppure è possibile scrivere una funzione (forse una in linea) per ciascun tipo.

+2

+1 Wow: - |, non sapevo davvero di '({...})'. Dovrebbero metterlo completamente nella lingua. – cnicutar

+2

Grazie per il collegamento ['({...})'] (http://gcc.gnu.org/onlinedocs/gcc-4.6.1/gcc/Statement-Exprs.html#Statement-Exprs)! È sempre difficile google con solo punteggiatura. – Halst

10

È un'estensione GCC. L'operatore virgola non funziona:

// C89, doesn't work... 
#define max(a,b) \ 
    (typeof (a) _a = (a), \ 
    typeof (b) _b = (b), \ 
    (_a > _b ? _a : _b)) 

operatore La virgola funziona solo con le espressioni, e typeof(a) _a = (a); è una dichiarazione, non è un'espressione. Non è davvero possibile scrivere una macro equivalente senza estensioni GCC o C11, che ha _Generic. Nota che typeof è anche un'estensione GCC, quindi non ottieni alcuna portabilità eliminando ({...}) a meno che non elimini anche typeof.

Ecco una versione C11, notare quanto è prolissa al confronto (e gestisce solo due tipi!). C11 non è nemmeno ancora supportato, buona fortuna cercando di trovare un compilatore per testare questo:

// C11 
static inline int maxi(int x, int y) { return x > y ? x : y; } 
static inline long maxl(long x, long y) { return x > y ? x : y; } 
#define max(x, y) _Generic((x), \ 
    long: maxl(x,y), \ 
    int:_Generic((y), \ 
     int: maxi(x,y), \ 
     long: maxl(x,y))) 

In portatile C99, è possibile scrivere una funzione macro o in linea che consente di ottenere lo stesso effetto, ad eccezione solo sarà lavoro per un tipo per macro.

// C99 
static inline int maxi(int x, int y) { return x > y ? x : y; } 

In C89/C90, non riesco a pensare a un modo di scrivere la macro in modo tale che non valuterà x o y due volte.

+7

Si prega di non scrivere una risposta che non dice nulla. Aspetta il tuo tempo e scrivi una buona risposta. Otterrà un sacco di upvotes se è buono. Non c'è bisogno di provare e rivendicare la domanda come la tua. –

+0

Scusa, sono su un terminale sconosciuto e sto cercando di salvare le bozze in modo da non perdere ciò che scrivo. Non sto davvero cercando di "rivendicare la domanda come mia". –

+1

Ok, +1 ora, ottima risposta –

Problemi correlati