在Linux内核源遇到深奥的#define宏(Abstruse #define macro enco

2019-07-29 00:06发布

其被定义为下面的get_cpu_var marcro

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

似乎难以理解be.I我假定它是一种功能的宏它会返回一个变量的指针(基于星号),或者是某种功能pointer.Am的我甚至接近它?谁能赐教吗?

Answer 1:

你的开口之间看到({})是一个语句表达 - GCC编译器的非标准的特征,它允许一个嵌入化合物语句转换为C表达式。 这样声明表达的结果是内部的非常最后一个表达式语句中的({}) 你的情况,这将是&__get_cpu_var(var)

&操作者施加到的结果__get_cpu_var(var)子表达式。 这意味着, __get_cpu_var返回左值。 如果这确实是C,那么__get_cpu_var也必须是一个宏观的,因为在C语言函数不能返回左值。

&操作者产生一个指针,它然后通过解除引用(整个语句表达的结果) *操作者存在于上述宏定义的最开始。 所以,上面的宏基本上相当于*&__get_cpu_var(var)的表达。

有些人可能会问,为什么它是为实现*&__get_cpu_var(var)而不仅仅是__get_cpu_var(var) 这是这样做的方式来保存的结果lvalueness __get_cpu_var(var) 语句表达式的结果始终是一个右值,即使里面的最后stetement的({})是一个左值。 为了保持结果的lvalueness知名*&使用技巧。

这招不限于以任何方式GCC的语句表达。 这是比较常用于普通的日常C编程使用。 例如,假设你有两个变量

int a, b;

和你想写,将返回是表达式ab作为左值(比方说我们想给42吧)取决于选择的变量select 。 一个天真的尝试可能如下所示

(select ? a : b) = 42;

这是行不通的,因为C语言?:运营商失去了它的操作数的lvalueness。 其结果是一个rvalue,它不能分配给。 在这种情况下, *&伎俩来救援

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

现在它按预期工作。

这就是如何以及为什么楼主的宏定义包含了一个看似多余的应用程序*& 。 因此,你可以用上面的get_cpu_var宏观上assgnment两侧

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

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

在C ++语言相同的效果是通过使用参考来实现。 在C中有没有提及,所以我们使用的技巧,比如这个代替。



文章来源: Abstruse #define macro encountered in Linux kernel source