Abstruse #define macro encountered in Linux kernel source

c, c-preprocessor, gcc, linux-kernel

Solution

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_var` returns an lvalue. If this is indeed C, then `__get_cpu_var` must 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

int a, b;

and you want to write an expression that would return either `a` or `b` as an lvalue (let's say we want to assign `42` to it) depending on the selector variable `select`. A naive attempt might look as follows

(select ? a : b) = 42;

This 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 rescue

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

and 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 above `get_cpu_var` macro on either side of an assgnment

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

without that trick you'd only be able to use `get_cpu_var` on 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.

Problem

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?

Original source