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.
por lo que el * (...) es un encasillado para el resultado? * edited.noted y gracias. –
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
@Anthales: Agregué la respuesta sobre – AnT