我有一个很长的代码,被称为数百万的时间, 我注意到,如果我将所有宏更改为内联函数,代码运行速度会快得多。
你能解释一下这是为什么吗? Aren的宏只是一个文本替换?与可以调用函数的内联函数相反?
答案 0 :(得分:8)
宏是文本替换,因此通常会生成更多可执行代码。每次调用宏时,都会插入代码(好吧,不一定,宏可能是空的......但原则上) 另一方面,内联函数可能与宏一样工作,但它们也可能根本没有内联。
一般来说,inline
关键字是一个弱提示,而不是一个要求,编译器现在明智地内联函数(或将放弃这样做)基于启发式,主要是伪指令的数量。
内联函数可能因此导致编译器根本不内联该函数,或者将其内联几次,然后再将其称为非内置函数。
令人惊讶的是,内联可能实际上比内联更快,因为它减少了整体代码大小,从而减少了缓存和TLB未命中的数量。
答案 1 :(得分:7)
这取决于您正在使用的特定宏和函数调用。特定的宏实际上可以编译为比内联函数更长的操作集。通常最好不要将宏用于某些进程。内联函数将允许编译器键入检查并优化各种进程。宏会受到许多错误的影响,实际上可能导致各种低效率(例如必须将变量移入和移出存储空间)。
在任何情况下,由于您实际上在代码中看到了这种情况,您可以告诉编译器能够优化内联代码而不是盲目地放入文本扩展。
请注意,Google搜索“宏与内联”会对此进行一系列讨论。
答案 2 :(得分:6)
除了强制内联外,如果不仔细编写宏而不是两次评估他们的论点,那么宏也可能对速度有害。以这个类似函数的小宏及其内联函数为例:
#define square(x) ((x)*(x))
inline long square(long x) { return x*x; }
现在,当您使用变量square(foo)
调用它们时,它们是等效的。宏观扩展到((foo)*(foo))
,这是一个乘法,就像函数内联一样。
但是,如果您使用square(expensiveComputation(foo))
调用它们,则宏的结果是,expensiveComputation()
被调用两次。相反,内联函数的行为与任何函数类似:在执行函数体之前,它的参数被计算一次。
当然,您可以使用复合语句的gnu扩展名来编写宏(有关此文档,请参阅http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html)以避免双重评估,如下所示:
#define square(x) ({ \
long square_temp_variable = (x); \
square_temp_variable*square_temp_variable; \
})
但这很麻烦,它使代码无法移植。因此,最好坚持使用内联函数。
答案 3 :(得分:3)
一般来说,只要有可能,就可以通过内联函数替换函数样式宏。
不仅你会发现一些令人讨厌的陷阱a = MIN(i++, 50)
,例如你也获得了类型安全性,正如在一些评论中已经说明的那样,你避免多次评估争论,这可能会对表现产生非常不利的影响。