学习C++语言中的内联函数

226 阅读5分钟

在C++中,当一个普通的函数被调用时,有些人只是为了调用该函数而被监听。实际上,在函数真正开始执行之前,调用一个函数需要时间。从函数被调用到函数真正开始执行的这段时间被称为切换时间。如果普通函数很大,意味着它需要很长时间来执行,那么切换时间就相对较小,用户可以忽略它。然而,如果正常函数很小,就像许多函数一样,那么切换时间,对于大函数和小函数来说大致相同,不应该被忽略。在许多情况下,切换时间比小函数真正执行的时间要长;在某些情况下,要长很多。

为了解决这个问题,C++使用了宏和内联函数。宏就像一个小函数,但它通常比典型的小函数要短。最长的宏仍然是一个 "语句"。一个函数体可以有一个以上的语句。与普通的小函数相比,内联小函数有一些优势。

当一个宏被定义后,它将在程序中稍后被调用。内联函数也是先定义,然后再在程序中调用。普通函数被定义,然后在程序中稍后被调用。所有这三种类型的函数都是在程序中定义并在后面调用的。它们中的任何一个都可以被多次调用。

当宏和小的内联函数在程序中后期被调用时,它们与正常的方法函数不同。C++编译器将定义的宏代码或定义的小内联函数代码(主体)放在程序中被调用的地方。当编译器这样做时,编译器就被称为扩展了宏或内联函数。而普通函数则不是这样的。普通函数没有被扩展,它是在哪里被调用的。

普通函数的调用需要切换时间,以便在执行前正确断言该函数,而宏或小的内联函数只要被调用就开始执行,没有切换时间的浪费。这就是宏和小内联函数比普通函数的主要优势,即省去了切换时间。

本文解释了C++中的内联函数与宏的比较。给出了对宏的解释。在文章的最后,对内联函数和普通函数做了一个比较。

注:在程序中调用一个宏,可以说是在调用该宏。

文章内容

定义宏和内联函数

类对象宏和内联变量
有一个类对象宏,也有一个类函数宏。相应地,有内联变量和内联函数。考虑一下下面的C++程序。

#include
using namespace std;

#define var1 "E"

inline char var2 = 'E';

int main()
{
        cout << var1 << endl;
        cout << var2 << endl;

        return 0;
}

输出结果是。

E  
E

这个程序有一个类似对象的宏和一个内联变量。每个变量都持有一个值,'E'。一个类似对象的宏以#define开始,没有类型指示符。内联变量以 "inline "开头,后面有类型指示符。与内联类型相比,宏有一个缺点,因为它们没有指示类型。这可能导致程序中的类型不匹配问题。在main()函数中,var1和var2分别是不同变量的定义代码。

注意:不清楚var1存放的是char还是字面字符串。另外,请注意,一个宏,无论是类似对象还是类似函数,都不会以分号结束。它是通过按回车键结束的。内联变量或内联函数则以各自的正常方式结束。

**类函数宏和内联函数
**类函数宏是一个需要参数的宏。与类函数宏一样,无论类函数宏在程序中被调用到哪里,编译器都会用代码定义代替调用,并在运行时消除切换时间(函数调用开销)。

内联函数是一个以 "内联 "开头的函数。它的返回类型和参数类型比类函数宏有优势。类函数宏没有参数类型和返回类型。它的返回类型是宏名称的最终值。

下面的C++程序有一个类函数宏和一个内联函数,它们各自寻找两个参数的最大值。内联函数对两个整数进行比较,并返回较大的那个整数。内联函数的返回值可以被分配给一个新的int变量。另一方面,宏的最终值成为宏的值。

#include
    using namespace std;

    #define maxM(a, b) ((a) > (b) ? (a): (b))

    inline int maxI(int a, int b) {
        if (a > b)
            return a;
        if (a < b)
            return b;
        if (a == b)
            return a;
    }

    int main()
    {
        cout << maxM(2.5, 6) << endl;
        cout << maxI(3, 7) << endl;

        return 0;
    }

输出结果是。

6  
7

在宏中,参数应该是兼容的类型。这使宏比内联函数具有某种优势,在这种情况下,内联函数的参数类型应该是相同的。

这个宏的名字是maxM。参数是a和b,其余部分是一种函数体,用圆括号划定。它说如果(a)>(b)为真,那么a成为宏的值;否则,b成为宏的值。

内联函数和编译器

在编译器用函数的定义代码替换了内联函数调用后,程序仍然要运行。编译不是在运行或执行程序。对于普通函数,开销(切换时间)发生在程序运行(执行)时。宏或内联替换发生在编译期间,也就是执行之前(在程序被发送给客户或用户之前)。

最后,对于宏和小型内联函数来说,切换时间被省略或获得。然而,如果内联函数很大,编译器将决定是否将该函数声明为内联,内联,或不内联。如果被声明为内联的函数很大,那么用其函数代码的主体来替换其任何调用可能没有明显的收益。至于编译器决定的标准,--见下文。

注意:一个定义在类定义中的函数是一个内联函数,前面有内联指定符。

宏和内联函数的比较

宏可以与不同的类型工作,只要它们是兼容的。这是一个优势。然而,这也导致了副作用,然后就有了缺点。内联函数会在使用参数之前测试其参数类型的有效性,这就避免了副作用。

比较内联函数和普通函数

内联函数的优点

  • 没有函数调用的开销(没有切换时间)。
  • 当普通函数返回时也有开销。使用内联函数,没有返回调用的开销。
  • 有了内联函数,就有可能对函数体进行特定环境的优化。

内联函数的缺点

  • 对于内联函数的每一次调用,函数定义(主体)代码都是重复的(被编译器重打)。这可能导致一个非常大的、二进制的(编译)文件。
  • 编译器需要很长的时间来编译,因为它为所有的调用重复了相同的代码。

许多嵌入式系统可能不需要内联函数,因为较小的程序规模比较高的速度更可取。

还有其他的缺点--见下文。

结论

内联函数就像一个宏。它们有相同的目的。定义代码取代了每个调用或函数调用。然而,内联函数比宏有更多的优势。有类似对象的宏,也有相应的内联变量。 有类似函数的宏,也有相应的内联函数。一个定义在类中的函数是一个内联函数,无论内联指定符是否在它前面。

要定义一个类对象宏或类函数宏,请在它前面加上#define,然后是宏的名字。该宏不指定其值类型或参数类型。要定义一个内联变量或内联函数,在它前面加上指定符inline,然后是返回类型,最后是名称。对于内联函数,返回类型和参数类型都是精确的。副作用是可以避免的。

与宏相比,内联函数具有整体优势。当内联函数与普通函数相比,有优点也有缺点。