[英]Abstruse #define macro encountered in Linux kernel source
如下定义的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); }))
我想这是一种返回宏(基于星号)的变量指针的函数宏,或者它是某种函数指针,我什至接近它吗?有人可以启发我吗?
您在开头({
和结尾})
之间看到的是语句表达式 -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)
即使({})
内部的最后一步是左值,语句表达式的结果也始终是右值。 为了保持结果的左值性,使用了众所周知的*&
技巧。
此技巧绝不限于GCC语句表达式。 在普通的日常C编程中相对经常使用它。 例如,假设您有两个变量
int a, b;
并且您想编写一个表达式,该表达式根据选择器变量select
,将返回a
或b
作为左值(假设我们要为其分配42
)。 天真的尝试可能如下所示
(select ? a : b) = 42;
这是行不通的,因为在C语言中, ?:
运算符失去了其操作数的左值性。 结果是一个右值,无法将其分配给它。 在这种情况下, *&
技巧可以解决
*(select ? &a : &b) = 42;
现在它可以按预期工作了。
这正是原始海报的宏定义包含*
和&
的看似多余的应用的方式和原因。 因此,您可以在组件的任一侧使用上面的get_cpu_var
宏
something = get_cpu_var(something);
get_cpu_var(something) = something;
没有这种技巧,您只能在右侧使用get_cpu_var
。
在C ++语言中,使用引用可以达到相同的效果。 在C语言中,我们没有引用,因此我们使用了类似的技巧。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.