2012-04-15 51 views
6

其定义如下奥的#define宏

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

的get_cpu_var marcro似乎难以理解be.I我假定这是一种功能宏它会返回一个变量的指针(基于星号)或者它是某种函数指针。我甚至可以接近它吗?任何人都可以启发我吗?

回答

15

你开口({})之间看到什么是语句表达 - 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)。这样做是为了保留__get_cpu_var(var)结果的。语句表达式的结果总是一个右值,即使({})内的最后一步是左值。为了保持结果的公正性,使用了熟知的*&技巧。

这个技巧并不限于GCC语句表达式。它比较常用于日常的C编程。例如,假设你有两个变量

int a, b; 

和你想写,将返回要么ab作为左值表达式(假设我们想给42的话)取决于选择的变量select。一个天真的尝试可能如下

(select ? a : b) = 42; 

这在C语言中是行不通的,因为?:运营商失去了它的操作数的lvalueness。结果是一个不能分配的右值。在这种情况下*&技巧来拯救

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

现在它按预期工作。

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

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

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

在C++语言中,使用引用可以获得相同的效果。在C中我们没有引用,所以我们使用这样的技巧来代替。

+0

所以*(...)是结果的类型转换吗? *编辑。注意和谢谢。 – 2012-04-15 21:36:54

+0

所以这基本上返回'*&__get_cpu_var(var)' - 但他们为什么不简单地返回'__get_cpu_var(var)'?某种编译时类型检查? – Anthales 2012-04-15 21:42:55

+1

@Anthales:我在上面加了 – AnT 2012-04-15 21:51:16