2009-08-06 5 views
29

Navigando nei sorgenti del kernel Linux ho trovato some piece of code dove un blocco di istruzioni circondato da parentesi viene trattato come un'espressione a la lisp (o ML), ovvero un'espressione il cui valore è il valore dell'ultima istruzione.Sono dichiarazioni composte (blocchi) circondate da espressioni paren in ANSI C?

Ad esempio:

int a = ({ 
    int i; 
    int t = 1; 
    for (i = 2; i<5; i++) { 
     t*=i; 
    } 
    t; 
}); 

Ho cercato in ANSI C grammar cercando di capire come questo pezzo di codice si adatterebbe nella albero sintattico, ma non ho avuto successo.

Quindi, qualcuno sa se questo comportamento è richiesto dallo standard o è solo una peculiarità di GCC?

Aggiornamento: Ho provato con la bandiera -pedantic e il compilatore ora mi dà un avvertimento:

warning: ISO C forbids braced-groups within expressions 

risposta

28

Si chiama "gruppo rinforzato all'interno di espressione".

Non consentito da ANSI/ISO C né C++ ma gcc lo supporta.

+7

È possibile sopprimere l'avviso in GCC inserendo "__extension__" prima della parentesi di apertura. – Flimm

28

Questa è un'estensione statement expressions, , è possibile trovare l'elenco completo di estensioni C here. Questo è in realtà uno degli many gcc extensions used in the Linux kernel e sembra che sia clang supports this too e sebbene non sia esplicitamente nominato nel documento.

Come si osserva l'ultima espressione funge da valore dell'espressione, dice il documento (sottolineatura mia):

L'ultima cosa nella dichiarazione composto deve essere l'espressione seguita da un punto e virgola ; il valore di questa sottoespressione funge da valore dell'intero costrutto. (Se si utilizza un altro tipo di dichiarazione la scorsa all'interno delle parentesi, il costrutto è tipo void, e così efficacemente alcun valore.)

Uno dei principali vantaggi potrebbe essere quella di rendere sicuri macro che eviterebbe multipla valutazioni di argomenti con effetti collaterali. L'esempio dato utilizza questa macro non sicuro:

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

che valuta sia a o b due volte e può essere riscritta per eliminare questo problema utilizzando espressioni economico come segue:

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

Nota, la necessità di utilizzare in modo esplicito int che può fissa utilizzando un altro gcc estensione Typeof:

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

Notare che clang also supports typeof.

+0

È possibile scrivere una macro per essere sicura in questo modo senza espressioni di istruzioni? – Flimm

+0

@Flimm Io non la penso così, ma non mi considererei un esperto di macro. Li evito il più possibile, anche se ci sono alcuni casi che sono difficili da evitare, come ad esempio la tua affermazione. –

+0

@Flimm Dipende da cosa vuoi fare la tua macro, in alcuni casi è certamente possibile scrivere una macro sicura. Per la funzionalità completa di 'max', non ti cadrà in alcun modo, qualunque cosa tu faccia in C standard, il problema è che devi conoscere il tipo di argomenti o devi valutare uno di loro due volte (di cui il più avanti è il problema con l'approccio macro sopra). – skyking