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

在Linux内核源代码中遇到Abstruse #define宏,第1张

概述get_cpu_var marcro,定义如下 29 #define get_cpu_var(var) (*({ \ 30 extern int simple_identifier_##var(void); \ 31 preempt_disable(); 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语言中函数不能返回lvalues.

& operator生成一个指针(整个语句表达式的结果),然后由上面宏定义开头的*运算符取消引用.因此,上面的宏基本上等同于*& __ get_cpu_var(var)表达式.

有些人可能会问为什么它被实现为*& __ get_cpu_var(var)而不仅仅是__get_cpu_var(var).这样做是为了保留__get_cpu_var(var)结果的左值.语句表达式的结果总是一个rvalue,即使({})中的最后一个stetement是一个左值.为了保持结果的左值,众所周知的*&使用技巧.

这个技巧不仅限于GCC语句表达式.它通常用于普通的日常C编程.例如,假设您有两个变量

int a,b;

并且你想要写一个表达式,它将a或b作为左值返回(假设我们想为它分配42),具体取决于选择器变量select.天真的尝试可能如下所示

(select ? a : b) = 42;

这不起作用,因为在C语言中,?:运算符失去了其 *** 作数的左值.结果是rvalue,无法分配.在这种情况下,*&诀窍来救援

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

现在它按预期工作.

这正是原始海报宏定义包含*和&的看似冗余应用的方式和原因.因此,您可以在assgnment的任何一侧使用上面的get_cpu_var宏

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

如果没有这个技巧,你只能在右侧使用get_cpu_var.

在C语言中,通过使用引用可以实现相同的效果.在C中我们没有引用,所以我们使用这样的技巧.

总结

以上是内存溢出为你收集整理的在Linux内核源代码中遇到Abstruse #define宏全部内容,希望文章能够帮你解决在Linux内核源代码中遇到Abstruse #define宏所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/1048018.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存