Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstruse #define macro encountered in Linux kernel source

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?

like image 328
Kooi Nam Ng Avatar asked Apr 15 '12 21:04

Kooi Nam Ng


People also ask

What is the synonym abstruse?

esoteric, perplexing, abstract, complex, complicated, deep, enigmatic, heavy, hidden, incomprehensible, intricate, involved, muddy, obscure, profound, puzzling, recondite, subtle, unfathomable, vague.

What is an abstruse person?

Abstruse means difficult to understand; obscure. Obtuse refers to an angle exceeding 90 degrees but less than 180 degrees. It also can refer to someone who is slow to understand, lacking sharpness or quickness of intellect.

Can we use abstruse for a person?

Abstruse is used to describe things that aren't easily accessible to the lay reader or average person. Specifically, it suggests the use of language or other material that suits the advanced levels of a subject of which the rest of us might have only an elementary understanding.

How do you use abstruse in a sentence?

The abstruse imagery of his work has produced a large corpus of diverging interpretations. No financial statement was too intricate for her, and no contract too abstruse. Among the words, many are unusual and some are abstruse. Some critics disliked the abstruse plot and deliberately enigmatic ending.


1 Answers

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.

like image 177
AnT Avatar answered Sep 21 '22 16:09

AnT