The get_cpu_var marcro which is defined as below
29 #define get_cpu_var(var) (*({ \
30 extern int simple_identifier_##var(void); \
31 preempt_disable(); \
32 &__get_cpu_var(var); }))
seems incomprehensible to be.I am supposing it was one kind of function macro which return a variable pointer(based on the asterisk) or is it some kind of function pointer.Am I even close to it?Could anyone enlighten me?
What you see between the opening
({and closing})is a statement expression – a non-standard feature of GCC compiler, which allows one to embed compound statements into C expressions. The result of such statement expression is the very last expression statement inside the({}). In your case that would be&__get_cpu_var(var).The
&operator is applied to the result of__get_cpu_var(var)subexpression. That implies that__get_cpu_varreturns an lvalue. If this is indeed C, then__get_cpu_varmust also be a macro, since in C language functions cannot return lvalues.The
&operator produces a pointer (the result of the entire statement expression), which is then dereferenced by a*operator present at the very beginning of the above macro definition. So, the above macro is essentially equivalent to the*&__get_cpu_var(var)expression.Some might ask why it is implemented as
*&__get_cpu_var(var)and not just__get_cpu_var(var). This is done that way to preserve the lvalueness of the result of__get_cpu_var(var). The result of statement expression is always an rvalue, even if the last stetement inside the({})was an lvalue. In order to preserve the lvalueness of the result the well-known*&trick is used.This trick is not limited to GCC statement expressions in any way. It is relatively often used in ordinary everyday C programming. For example, imagine you have two variables
and you want to write an expression that would return either
aorbas an lvalue (let’s say we want to assign42to it) depending on the selector variableselect. A naive attempt might look as followsThis will not work, since in C language the
?:operator loses the lvalueness of its operands. The result is an rvalue, which cannot be assigned to. In this situation the*&trick comes to the rescueand now it works as intended.
This is exactly how and why the original poster’s macro definition contains a seemingly redundant application of
*and&. Because of that you can use the aboveget_cpu_varmacro on either side of an assgnmentwithout that trick you’d only be able to use
get_cpu_varon the right-hand side.In C++ language the same effect is achieved by using references. In C we have no references, so we use tricks like this instead.