内联函数与预处理器宏

内联函数与预处理器宏有什么不同?

87827 次浏览

关键区别在于类型检查。编译器将检查作为输入值传递的内容是否属于可以传递到函数中的类型。对于预处理器宏来说,情况并非如此——它们在任何类型检查之前都会被扩展,这可能会导致严重且难以检测到的错误。

这里列出了其他几个不那么明显的要点。

内联函数在语法上与普通函数一样,提供类型安全性和函数局部变量的作用域,以及对类成员(如果它是一个方法)的访问。 此外,在调用内联方法时,必须遵守私有/受保护的限制。

内联函数将维护值语义,而预处理程序宏只复制语法。如果多次使用参数,预处理宏可能会出现非常微妙的错误——例如,如果参数包含像“ i + +”这样的变异,那么执行两次是相当令人惊讶的。内联函数不会有此问题。

预处理器宏只是应用于代码的替换模式。它们几乎可以在代码中的任何地方使用,因为在任何编译开始之前都会用它们的扩展替换它们。

内联函数是实际的函数,其主体直接注入到它们的调用站点中。它们只能在适当的函数调用情况下使用。

现在,至于在类函数上下文中使用宏和内联函数,请注意:

  • 宏不是类型安全的,并且可以展开,无论它们的语法是否正确——编译阶段将报告由宏展开问题引起的错误。
  • 宏可以在您意想不到的上下文中使用,从而导致问题
  • 宏更加灵活,因为它们可以扩展其他宏——而内联函数不一定这样做。
  • 由于宏的扩展,可能会导致副作用,因为输入表达式出现在模式中的任何位置都会被复制。
  • 并不总是保证内联函数是内联的——有些编译器只在发布版本中或者专门配置它们时才这样做。此外,在某些情况下内联可能是不可能的。
  • 内联函数可以为变量(特别是静态变量)提供作用域,预处理器宏只能在代码块{ ... }中执行此操作,静态变量的行为不会完全相同。

宏忽略了名称空间,这使它们变得邪恶。

首先,预处理宏只是编译之前代码中的“复制粘贴”。所以不存在 打字检查,一些 副作用可以出现

例如,如果要比较两个值:

#define max(a,b) ((a<b)?b:a)

例如,如果使用 max(a++,b++),就会出现副作用(ab将增加两次)。 相反,使用(例如)

inline int max( int a, int b) { return ((a<b)?b:a); }

在 GCC 中(其他的我不确定) ,内联声明一个函数,只是对编译器的一个提示。每当调用函数体时,是否包含函数体仍然取决于编译器在一天结束时的决定。

内联函数和预处理器宏之间的差异相对较大。预处理器宏只是一天结束时的文本替换。您放弃了编译器对参数和返回类型执行类型检查的许多能力。对参数的求值是非常不同的(如果你传递给函数的表达式有副作用,那么调试将会非常有趣)。在函数和宏的使用位置上存在细微的差别。例如,如果我有:

#define MACRO_FUNC(X) ...

其中 MACRO _ FUNC 明显定义了函数体。需要特别注意,以便在所有情况下都可以使用函数正确运行,例如,编写不良的 MACRO _ FUNC 将导致

if(MACRO_FUNC(y)) {
...body
}

使用普通函数不会有任何问题。

要向已给出的函数添加另一个差异: 不能单步执行调试器中的 #define,但可以单步执行内联函数。

从编码的角度来看,内联函数就像一个函数。因此,内联函数和宏之间的差异与函数和宏之间的差异是相同的。

从编译的角度来看,内联函数类似于宏。它被直接注入到代码中,而不是被调用。

一般来说,您应该将内联函数看作是混合了一些次要优化的正则函数。和大多数优化一样,编译器决定它是否真的关心应用它。由于各种原因,编译器通常会很高兴地忽略程序员内联函数的任何尝试。

内联函数类似于宏(因为函数代码是在编译时调用时展开的) ,内联函数由编译器解析,而宏由预处理器展开。因此,两者之间存在几个重要差异:

—— 文章不错: Http://www.codeguru.com/forum/showpost.php?p=1093923&postcount=1

;

如果内联函数中存在任何迭代或递归语句,那么它将表现为函数调用,以防止重复执行指令。节省程序的整体内存非常有帮助。

内联函数由编译器展开,而宏则由预处理器展开,这仅仅是文本替换。

因此,

  • 在宏调用期间不进行类型检查,而在函数调用期间进行类型检查。

  • 在宏观扩张过程中,由于重新评估论点和操作顺序,可能会出现意想不到的结果和效率低下的情况。例如:

    #define MAX(a,b) ((a)>(b) ? (a) : (b))
    int i = 5, j = MAX(i++, 0);
    

    会导致

    int i = 5, j = ((i++)>(0) ? (i++) : (0));
    
  • 在宏展开之前不计算宏参数

     #include <stdio.h>
    #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 关键字不能像函数那样在宏中用于返回值。

  • 可以重载内联函数。

  • 传递给宏的令牌可以使用称为 令牌粘贴操作符的操作符 ##进行连接。

  • 宏通常用于代码重用,其中内联函数用于消除函数调用期间的时间开销(多余时间)(避免跳转到子例程)。

#include<iostream>
using namespace std;
#define NUMBER 10 //macros are preprocessed while functions are not.
int number()
{
return 10;
}
/*In macros, no type checking(incompatible operand, etc.) is done and thus use of micros can lead to errors/side-effects in some cases.
However, this is not the case with functions.
Also, macros do not check for compilation error (if any). Consider:- */
#define CUBE(b) b*b*b
int cube(int a)
{
return a*a*a;
}
int main()
{
cout<<NUMBER<<endl<<number()<<endl;
cout<<CUBE(1+3); //Unexpected output 10
cout<<endl<<cube(1+3);// As expected 64
return 0;
}

宏通常比函数快,因为它们不涉及实际的函数调用开销。

宏的一些缺点: 没有类型检查。很难调试,因为它们会导致简单的替换。宏没有名称空间,因此代码中某个部分中的宏可能会影响其他部分。宏可能会导致如上面 CUBE ()示例所示的副作用。

宏通常是一行。但是,它们可以由多行组成。函数中没有这样的约束。

要知道 宏和内联函数之间的区别,首先我们应该知道它们到底是什么,以及什么时候应该使用它们。

函数 :

int Square(int x)
{
return(x*x);
}


int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
  • 函数调用具有与它们相关联的开销。函数执行完成后,它需要知道返回到哪里,因此在调用函数之前,它将返回地址存储在堆栈上。对于小型应用程序来说,这可能不是问题,但是在金融应用程序中,每秒钟发生数千个事务,函数调用可能太昂贵了。

马克罗斯:

# define Square(x) x*x;
int main()
{
int value = 5;
int result = Square(value);
cout << result << endl;
}
  • 宏应用于预处理阶段。在这个阶段,使用 #define关键字编写的语句将被替换或扩展

Int result = Square (x * x)

但宏可能导致意外行为。

#define Square(x) x*x
int main()
{
int val = 5;
int result = Square(val + 1);
cout << result << endl;
}

这里的输出是 11,而不是36。

内联函数 :

inline int Square(int x)
{
return x * x;
}


int main()
{
int val = 5;
int result = Square(val + 1);
cout << result << endl;
}

输出: 36

inline关键字要求编译器将函数调用替换为函数体。这里输出是正确的,因为它首先计算表达式,然后使用结果来执行函数体。内联函数减少了函数调用开销,因为不需要将返回地址或函数参数存储到堆栈中。

宏和内联函数的比较:

  1. 宏通过文本替换工作,而内联函数则复制函数的逻辑。
  2. 宏由于替换而容易出错,而内联函数可以安全使用。
  3. 宏不能分配给函数指针; 内联函数可以。
  4. 宏很难与多行代码一起使用,而内联函数则不然。
  5. 在 C + + 中,宏不能与成员函数一起使用,而内联函数可以。

结论:

内联函数有时比宏更有用,因为它们可以安全地使用,但也可以减少函数调用开销。 对于编译器来说,inline关键字是 请求,某些函数不会像下面这样内联:

  • 大功能
  • 有太多条件参数的函数
  • 递归代码和带循环的代码等。

这是一件好事,因为它允许编译器决定是否用另一种方式做事情会更好。