在Linux内核源代码中遇到深奥的#define宏 [英] Abstruse #define macro encountered in Linux kernel source

查看:100
本文介绍了在Linux内核源代码中遇到深奥的#define宏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这将在下面

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

似乎INCOM prehensible到be.I我假定这是一种功能宏它返回一个变量的指针(基于星号),或者是某种功能pointer.Am的我甚至接近它?莫非有人告诉我吗?

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?

推荐答案

在开幕之间看到的({和结束})语句前pression 的 - GCC编译器,它允许一个嵌入复合语句转换为C EX pressions的非标准功能。这种说法当然pression的结果是里面的最后EX pression语句 {} 。你的情况,这将是&放大器; __ get_cpu_var(VAR)

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).

&安培; 运算符应用于的__ get_cpu_var(VAR)的结果 SUBEX pression。这意味着, __ get_cpu_var 返回一个左值。如果这确实是C,那么 __ get_cpu_var 也必须是一个宏观的,因为在C语言函数不能返回左值。

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.

&安培; 运营商产生一个指针(整个语句前pression的结果),然后由一个间接引用 * 在上面的宏定义的开始运营present。所以,上面的宏基本上等同于 *放大器; __ get_cpu_var(VAR)前pression

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.

也许有人会问,为什么它是作为实施*放大器; __ get_cpu_var(VAR)而不仅仅是 __ get_cpu_var(VAR)。这是这样做的的__ get_cpu_var(VAR)的结果preserve的的 lvalueness 。声明前pression的结果始终是一个右值,即使 {} 是一个左值内的最后stetement。为了preserve结果的lvalueness著名的 *放大器; 招用。

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.

这招不限于GCC声明前pressions以任何方式。这是比较常用于普通平凡的C语言编程使用。例如,假设你有两个变量

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;

和你想要写一个前pression,将返回为 A B 作为一个左值(假设我们想给 42 来的话)取决于选择变量选择。一个天真的尝试可能如下所示

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;

这是行不通的,因为在C语言中的运营商失去了它的操作数的lvalueness。其结果是右值,不能被分配​​到。在这种情况下, *放大器; 招就派上用场了。

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.

这是究竟如何,为什么原来的海报的宏定义包含了一个看似多余的应用程序 * &安培; 。因此,你可以在一个assgnment两侧

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;

没有那招你只能够使用 get_cpu_var 在右侧。

在C ++语言相同的效果是通过使用获得的引用的。在C我们没有引用,所以我们使用的技巧是这样吧。

In C++ language the same effect is achieved by using references. In C we have no references, so we use tricks like this instead.

这篇关于在Linux内核源代码中遇到深奥的#define宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆