2009-08-06 3 views
29

Navegación por las fuentes del kernel de Linux que he encontrado some piece of code donde un bloque de instrucciones rodeadas por paréntesis se trata como una expresión a la Lisp (o ML), es decir, una expresión cuyo valor es el valor de la última declaración.¿Las sentencias compuestas (bloques) están rodeadas por expresiones parens en ANSI C?

Por ejemplo:

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

He estado buscando en la ANSI C grammar tratando de averiguar cómo esta pieza de código encajaría en el árbol de análisis, pero no he tenido éxito.

Entonces, ¿alguien sabe si este comportamiento es obligatorio por la norma o es solo una peculiaridad de GCC?

Actualización: He tratado con la bandera -pedantic y el compilador ahora me da una advertencia:

warning: ISO C forbids braced-groups within expressions 

Respuesta

28

Se llama "grupo arriostrados dentro de la expresión".

No está permitido por ANSI/ISO C ni C++, pero gcc lo admite.

+7

Puede suprimir la advertencia en GCC colocando '__extension__' antes del paréntesis de apertura. – Flimm

28

Esta es una extensión gcc llamada statement expressions, puede encontrar la lista completa de extensiones C here. Este es en realidad uno de los many gcc extensions used in the Linux kernel y parece que clang supports this too y aunque no se menciona explícitamente en el documento.

Como usted observó la última expresión sirve como el valor de la expresión, dice el documento (énfasis mío):

El última hora de la sentencia compuesta debe ser una expresión seguida por un punto y coma ; el valor de esta subexpresión sirve como el valor de la construcción completa. (Si utiliza algún otro tipo de declaración última dentro de las llaves, el constructo tiene tipo vacío, y por lo tanto efectivamente sin valor.)

Uno de los principales beneficios sería hacer seguras macros que evitarían múltiples evaluaciones de argumentos con efectos secundarios. El ejemplo que se utiliza esta macro insegura:

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

que evalúa ya sea a o b dos veces y se puede reescribir para eliminar este problema utilizando expresiones de los estados de la siguiente manera:

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

Tenga en cuenta, la necesidad de utilizar de manera explícita int que puede fijo utilizando otro gcc extensión Typeof:

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

Tenga en cuenta que clang also supports typeof.

+0

¿Es posible escribir una macro para estar seguro así sin expresiones de enunciado? – Flimm

+0

@Flimm No lo creo, pero no me consideraría un experto macro. Los evito tanto como puedo, aunque hay algunos casos que son difíciles de evitar, como lanzar tu propia afirmación. –

+0

@Flimm Depende de lo que desee que haga su macro, en algunos casos es ciertamente posible escribir una macro segura. Para la funcionalidad completa de 'máximo', se quedará corto de alguna manera, sin importar lo que haga en el estándar C, el problema es que o bien necesita saber el tipo de argumentos o tiene que evaluar uno de ellos dos veces (de los cuales el más adelante está el problema con el enfoque macro anterior). – skyking

Cuestiones relacionadas