在linux内核源代码中,我发现很多函数都采用内联形式实现的小体,还有很多其他函数也是用MACRO实现的小体。
所以我想知道在选择哪一个时所涉及的考虑是什么,因为我认为两者都是合适的。或者这只是个人风格?
答案 0 :(得分:1)
宏不进行类型检查并需要其他特殊注意事项(即只计算一次表达式),因此应尽可能避免使用它们。但是,不检查类型的优点是允许您在C89中编写通用函数。
同样编写真正的inline
函数允许(使用可以在内核配置中激活的某个标志)编译器如果具有性能优势也可以取消内联,而对于宏来说这是不可能的,简单的文字替换。
答案 1 :(得分:0)
宏是文本替换可以比内联函数做更多。它们也可能有不良副作用。考虑众所周知的交换宏。
#define SWAP(a,b) {int t=a; a=b; b=t}
并注意到SWAP(i,t[i])
做了不想要的事情。
内联函数的优点是具有类似语义的函数调用(参数被评估一次,等等......)。
所以这主要是编码风格,并认识到宏和&功能是不同种类的动物。
你的问题与内核没有特别的关系。任何C(甚至C ++)程序都有同样的问题。
答案 2 :(得分:0)
请记住,Linux内核中的很多代码已存在很长时间了。一些宏也对输入/环境的其他部分做了“聪明的东西”,而不是函数将/可能/应该做什么。
作为一般规则,尽可能使用(内联)函数,因为如上所述,函数的“陷阱”较少。
如果你做了聪明的替换或其他一些“只能在宏中做”,如果可能的话,最好制作一个形成函数参数的宏。例如。
#define ASSERT(x) do { if (!(x)) { fprintf(stderr, "Assertion failed on %s:%d", __FILE__, __LINE__); exit(1); } while(0);
可以完成:
#define ASSERT(x) do_assert(!!(x), __FILE__, __LINE__);
void do_assert(bool val, const char *file, int line)
{
if (!val)
{
fprintf(....);
exit(1);
}
}
现在,您可以在调试版本中,在if中的断言中设置断点,并且每当断言失败时,您都可以看到如何到达那里。使用宏,这是不可能的。
现代编译器在适当的情况下很好地内联,只有一半的机会。