2012-04-15 12 views
6

El marcro get_cpu_var que se define de la siguiente maneraAbstruse macro #define encontrado en las fuentes del núcleo Linux

29 #define get_cpu_var(var) (*({       \ 
30   extern int simple_identifier_##var(void);  \ 
31   preempt_disable();        \ 
32   &__get_cpu_var(var); })) 

parece incomprensible para be.I estoy suponiendo que era un tipo de macro función que devuelve un puntero variable (basada en el asterisco) o es una especie de puntero a la función. ¿Incluso estoy cerca de eso? ¿Podría alguien iluminarme?

Respuesta

15

Lo que se ve entre la apertura y el cierre de ({}) es una expresión comunicado - una característica no estándar del compilador GCC, lo que permite a incrustar las instrucciones compuestas en expresiones C. El resultado de dicha expresión de declaración es la última declaración de expresión dentro del ({}). En su caso, eso sería &__get_cpu_var(var).

El operador & se aplica al resultado de __get_cpu_var(var) subexpresión. Eso implica que __get_cpu_var devuelve un valor l. Si esto es realmente C, entonces __get_cpu_var también debe ser una macro, ya que en el lenguaje C las funciones no pueden devolver valores.

El operador & produce un puntero (el resultado de la expresión de la sentencia completa), que a continuación, se desreferencia por un operador * presente al principio de la definición de macro anterior. Por lo tanto, la macro anterior es esencialmente equivalente a la expresión *&__get_cpu_var(var).

Algunos podrían preguntarse por qué se implementa como *&__get_cpu_var(var) y no solo __get_cpu_var(var). Esto se hace de esa manera para preservar lvalueness del resultado de __get_cpu_var(var). El resultado de la expresión de declaración siempre es un valor r, incluso si el último stetement dentro del ({}) fue un valor l. Con el fin de preservar la lvaloriedad del resultado, se utiliza el bien conocido truco *&.

Este truco no está limitado a las expresiones de enunciados GCC de ninguna manera. Se usa con relativa frecuencia en la programación común de C cotidiano. Por ejemplo, imagine que tiene dos variables

int a, b; 

y desea escribir una expresión que volvería ya sea a o b como un valor-i (digamos que queremos asignar 42 a ella) en función del selector de variables select. Un intento ingenuo podría tener el siguiente

(select ? a : b) = 42; 

Esto no va a funcionar, ya que en lenguaje C ?: el operador pierde el lvalueness de sus operandos. El resultado es un valor r, que no se puede asignar a. En esta situación el *& truco viene al rescate

*(select ? &a : &b) = 42; 

y ahora funciona según lo previsto.

Esto es exactamente cómo y por qué la definición de macro del póster original contiene una aplicación aparentemente redundante de * y &.Debido a que puede utilizar el get_cpu_var macro anterior a cada lado de un assgnment

something = get_cpu_var(something); 
get_cpu_var(something) = something; 

sin ese truco que solo podrás utilizar get_cpu_var en el lado derecho.

En el lenguaje C++, se obtiene el mismo efecto utilizando las referencias . En C no tenemos referencias, así que usamos trucos como este en su lugar.

+0

por lo que el * (...) es un encasillado para el resultado? * edited.noted y gracias. –

+0

Esto básicamente devuelve '* & __get_cpu_var (var)' - pero ¿por qué simplemente no devolvieron '__get_cpu_var (var)'? Algún tipo de verificación de tipo de tiempo de compilación? – Anthales

+1

@Anthales: Agregué la respuesta sobre – AnT