zoukankan      html  css  js  c++  java
  • 内联函数

    在c++中,为了解决一些频繁调用的小函数大量消耗栈空间或者是叫栈内存的问题,特别的引入了inline修饰符,表示为内联函数。

      可能说到这里,很多人还不明白什么是栈空间,其实栈空间就是指放置程序的局部数据也就是函数内数据的内存空间,在系统下,栈空间是有限的,如果频繁大量的使用就会造成因栈空间不足所造成的程序出错的问题,函数的死循环递归调用的最终结果就是导致栈内存空间枯竭。

      下面我们来看一个例子:

    #include <iostream>
    #include <string>
    using namespace std;

    inline string dbtest(int a); //函数原形声明为inline即:内联函数


    void main()
    {
    for (int i=1;i<=10;i++)
    {
    cout << i << ":" << dbtest(i) << endl;
    }
    cin.get();

    }

    string dbtest(int a)//这里不用再次inline,当然加上inline也是不会出错的
    {
    return (a%2>0)?"奇":"偶";

    }

      上面的例子就是标准的内联函数的用法,使用inline修饰带来的好处我们表面看不出来,其实在内部的工作就是在每个for循环的内部所有调用dbtest(i)的地方都换成了(i%2>0)?"奇":"偶"这样就避免了频繁调用函数对栈内存重复开辟所带来的消耗。

      说到这里很多人可能会问,既然inline这么好,还不如把所谓的函数都声明成inline,嗯,这个问题是要注意的,inline的使用是有所限制的,inline只适合函数体内代码简单的函数使用,不能包含复杂的结构控制语句例如while switch,并且不能内联函数本身不能是直接递归函数(自己内部还调用自己的函数)。

      说到这里我们不得不说一下在c语言中广泛被使用的#define语句,是的define的确也可以做到inline的这些工作,但是define是会产生副作用的,尤其是不同类型参数所导致的错误,由此可见inline有更强的约束性和能够让编译器检查出更多错误的特性,在c++中是不推荐使用define的。

      关于内联函数的更多例子我就不一一举出了,灵活的使用也多靠学习者本身,我只在此抛砖引玉,让大家尽可能多的学习到c++中的一些新的先进的特性知识点。


    内联函数在编译层面类似于宏替换。也就是说,程序执行过程中调用内联函数不需要入栈出栈,所以效率会提高。

    C语言里面的内联函数(inline)与宏定义(#define)探讨

    先简明扼要,说下关键:
    1、内联函数在可读性方面与函数是相同的,而在编译时是将函数直接嵌入调用程序的主体,省去了调用/返回指令,这样在运行时速度更快。
    2、内联函数可以调试,而宏定义是不可以调试的。
    内联函数与宏本质上是两个不同的概念如果程序编写者对于既要求快速,又要求可读的情况下,则应该将函数冠以inline。下面详细介绍一下探讨一下内联函数与宏定义。

    一、内联函数是什么?
    内联函数是代码被插入到调用者代码处的函数。如同 #define 宏(但并不等同,原因见下文),内联函数通过避免被调用的开销来提高执行效率,尤其是它能够通过调用(“过程化集成”)被编译器优化。

    二、 内联函数是如何在安全和速度上取得折衷?
    在 C 中,你可以通过在结构中设置一个 void* 来得到“封装的结构”,在这种情况下,指向实际数据的 void* 指针对于结构的用户来说是未知的。因此结构的用户不知道如何解释void*指针所指内容,但是存取函数可以将 void* 转换成适当的隐含类型。这样给出了封装的一种形式。

    不幸的是这样做丧失了类型安全,并且也将繁琐的对结构中的每个域的访问强加于函数调用。(如果你允许直接存取结构的域,那么对任何能直接存取的人来说,了解如何解释 void* 指针所指内容就是必要的了;这样将使改变底层数据结构变的困难)。

    虽然函数调用开销是很小的,但它会被累积。C++类允许函数调用以内联展开。这样让你在得到封装的安全性时,同时得到直接存取的速度。此外,内联函数的参数类型由编译器检查,这是对 C 的 #define 宏的一个改进。

    三、为什么我应该用内联函数?而不是原来清晰的 #define 宏?

    因为#define宏定义函数是在四处是有害的:
    和 #define 宏不同的是,内联函数总是对参数只精确地进行一次求值,从而避免了那声名狼藉的宏错误。换句话说,调用内联函数和调用正规函数是等价的,差别仅仅是更快:
    // 返回 i 的绝对值的宏
    #define unsafe(i)
    ( (i) >= 0 ? (i) : -(i) )

    // 返回 i 的绝对值的内联函数
    inline
    int safe(int i)
    {
    return i >= 0 ? i : -i;
    }

    int f();

    void userCode(int x)
    {
    int ans;

    ans = unsafe(x++); // 错误!x 被增加两次
    ans = unsafe(f()); // 危险!f()被调用两次

    ans = safe(x++); // 正确! x 被增加一次
    ans = safe(f()); // 正确! f() 被调用一次
    }

    和宏不同的,还有内联函数的参数类型被检查,并且被正确地进行必要的转换。
    宏定义复杂函数是有害的;非万不得已不要用。

    四、如何告诉编译器使非成员函数成为内联函数?
    声明内联函数看上去和普通函数非常相似:
    void f(int i, char c);
    当你定义一个内联函数时,在函数定义前加上 inline 关键字,并且将定义放入头文件:
    inline
    void f(int i, char c)
    {
    // ...
    }

    注意:将函数的定义({...}之间的部分)放在头文件中是强制的,除非该函数仅仅被单个 .cpp 文件使用。尤其是,如果你将内联函数的定义放在 .cpp 文件中并且在其他 .cpp文件中调用它,连接器将给出 “unresolved external” 错误。

    五、如何告诉编译器使一个成员函数成为内联函数?
    声明内联成员函数看上去和普通函数非常类似:
    class Fred {
    public:
    void f(int i, char c);
    };

    但是当你定义内联成员函数时,在成员函数定义前加上 inline 关键字,并且将定义放入头文件中:
    inline
    void Fred::f(int i, char c)
    {
    // ...
    }
    通常将函数的定义({...}之间的部分)放在头文件中是强制的。如果你将内联函数的定义放在 .cpp 文件中并且在其他 .cpp 文件中调用它,连接器将给出“unresolved external”错误。

    六、 有其它方法告诉编译器使成员函数成为内联吗?
    有:在类体内定义成员函数:
    class Fred {
    public:
    void f(int i, char c)
    {
    // ...
    }
    };
    尽管这对于写类的人来说很容易,但由于它将类是“什么”(what)和类“如何”(how)工作混在一起.
    小结
    总之,在嵌入式C(或C++)编程里面,懂得使用内联函数(inline)与宏定义(#define),并使用好它们,对我们是大有裨益的。(注:本文部分内容来源于网络整理,上述探讨属于个人意见,仅供参考。错误之处也是难免!)

  • 相关阅读:
    图像处理、分析与机器视觉读书笔记-------第二章图像及其表达与性质
    win7下VS2015+opencv3.1.0配置
    简单使用普通用户启动tomcat
    漏洞扫描,linux配置规范处理
    linux防火墙开放和禁用指定端口
    CentOS自带定时任务crontab
    linux之dos2unix命令
    CentOS7时间设置问题
    shell去除换行和空格
    log4j日志输出级别高低
  • 原文地址:https://www.cnblogs.com/timssd/p/4078212.html
Copyright © 2011-2022 走看看