内联函数vs预处理器macros
内联函数与预处理器macros有什么不同?
预处理器macros只是应用于您的代码的替代模式。 它们几乎可以在代码中的任何地方使用,因为在编译开始之前,它们将被扩展replace。
内联函数是直接注入到其调用站点的实际函数。 它们只能在函数调用适当的地方使用。
现在,就像函数式的上下文中使用macros和内联函数一样,要注意的是:
- macros不是types安全的,可以扩展,不pipe它们是否合成正确 – 编译阶段将报告由macros扩展问题导致的错误。
- macros可以在你不期望的上下文中使用,从而导致问题
- macros是更灵活的,因为它们可以扩展其他的macros – 而内联函数不一定这样做。
- 由于macros的扩展,macros可能会产生副作用,因为inputexpression式会在模式中出现的任何位置复制。
- 内联函数并不总是保证内联 – 有些编译器只能在发布版本或者特别configuration的时候这样做。 而且,在某些情况下,内联可能是不可能的。
- 内联函数可以为variables提供范围(尤其是静态variables),预处理macros只能在代码块{…}中执行此操作,而静态variables的行为不会完全相同。
首先,编译前的预处理器macros只是代码中的“复制粘贴”。 所以没有types检查 ,可能会出现一些副作用
例如,如果你想比较2个值:
#define max(a,b) ((a<b)?b:a)
例如,如果使用max(a++,b++)
,则会出现副作用( a
或b
将递增两次)。 相反,使用(例如)
inline int max( int a, int b) { return ((a<b)?b:a); }
内联函数由编译器进行扩展,macros由预处理器进行扩展,这仅仅是文本replace。因此,
-
在macros调用期间没有types检查,而在函数调用期间完成types检查。
-
由于重新评估论点和操作顺序,在macros观扩张期间可能会出现不希望的结果和低效率。 例如
#define MAX(a,b) ((a)>(b) ? (a) : (b)) int i = 5, j = MAX(i++, 0);
会导致
int i = 5, j = ((i++)>(0) ? (i++) : (0));
-
在macros扩展之前,不会评估macros参数
#define MUL(a, b) a*b int main() { // The macro is expended as 2 + 3 * 3 + 5, not as 5*8 printf("%d", MUL(2+3, 3+5)); return 0; } // Output: 16`
-
在函数的情况下,return关键字不能在macros中使用来返回值。
-
内联函数可以被重载
-
传递给macros的令牌可以使用称为Token-Pasting操作符的operator ##连接起来。
-
macros通常用于代码重用,其中内联函数用于消除函数调用期间(避免跳转到子例程)的时间开销(多余的时间)。
关键的区别是types检查。 编译器将检查你作为input值传递的是可以传递给函数的types。 对于预处理器macros来说,情况并非如此 – 在进行任何types检查之前,这些macros都会被扩展,并且会导致严重且难以检测到的错误。
这里还有其他几个不太明显的要点。
为了给已经给出的区别添加另外一个区别:你不能在debugging器中遍历一个#define
,但是你可以通过一个内联函数。
macros忽略名称空间。 这使他们变得邪恶。
内联函数与macros类似(因为函数代码在编译时在调用点展开),内联函数由编译器分析,而macros由预处理器扩展。 因此,有几个重要的区别:
- 内联函数遵循所有在正常函数上执行的types安全协议。
- 内联函数使用与其他函数相同的语法指定,除了它们在函数声明中包含inline关键字。
- 作为parameter passing给内联函数的expression式被评估一次。
-
在某些情况下,作为parameter passing给macros的expression式可以被多次计算。 http://msdn.microsoft.com/en-us/library/bf6bf4cf.aspx
-
macros在预编译时扩展,不能用于debugging,但可以使用内联函数。
– 好文章 :http://www.codeguru.com/forum/showpost.php?p= 1093923 &postcount=1
;
内联函数将维护数值语义,而预处理器macros只是复制语法。 如果你多次使用参数,你可以用预处理macros得到非常微妙的错误 – 例如,如果参数包含像“i ++”这样的执行两次的突变是一个惊喜。 内联函数不会有这个问题。
内联functuion在语法上的行为就像一个正常的函数,为函数局部variables提供types安全性和范围,如果是方法,则为类成员提供访问权限。 另外,在调用内联方法时,您必须遵守私有/受保护的限制。
在海湾合作委员会(我不确定其他人),声明一个函数内联,只是提示编译器。 编译器在一天结束时仍然决定是否在被调用时包含函数的主体。
内联函数和预处理器macros之间的区别比较大。 预处理器macros只是在一天结束时的文本replace。 你放弃了编译器对参数和返回types进行types检查的能力。 对参数的评估是非常不同的(如果你传递给函数的expression式有副作用,那么debugging的时候就会有一个非常有趣的时间)。 函数和macros的使用位置有细微的差别。 例如,如果我有:
#define MACRO_FUNC(X) ...
MACRO_FUNC显然定义了函数的主体。 需要特别注意,以便在所有情况下都可以正常运行,例如,写得不好的MACRO_FUNC会导致错误
if(MACRO_FUNC(y)) { ...body }
一个正常的function可以用在那里没有问题。
从编码的angular度来看,内联函数就像一个函数。 因此,内联函数和macros之间的差异与函数和macros之间的差异是相同的。
从编译的angular度来看,内联函数与macros相似。 它被直接注入到代码中,而不是被调用。
一般来说,你应该把内联函数看作是一些常规的函数,并且会有一些小的优化。像大多数优化一样,编译器决定它是否真正在使用它。 通常编译器会高兴地忽略程序员为了内联函数而尝试的各种原因。
如果内联函数中存在任何迭代或recursion语句,则内联函数将作为函数调用行为,以防止重复执行指令。 这对于保存程序的整体内存非常有帮助。