繁体   English   中英

Linux内核源代码中遇到的#define宏

[英]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 ,将返回ab作为左值(假设我们要为其分配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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM