欢迎来到朵拉利品网
知识中心
资讯
  • 资讯
  • 产品
  • 供应商
您的位置: 朵拉利品网 >  知识中心 > 内联函数是在预处理 内联函数和编译预处理的区别是?
内联函数是在预处理 内联函数和编译预处理的区别是?
2019-07-24 20:23:59 来源:朵拉利品网

1, 内联函数和编译预处理的区别是?



预处理只是一种简单替代,内联函数比较安全,编译器会自动判断是否可以内联等。
用#define预处理的时候会有一些副作用
比如:
#define ADD(x) (x+1)*(x+1)
如果有代码想要先做a++,再做ADD,那可能就会有问题
ADD(a++)就成了((a++)+1)*((a++)+1)
然而用内联函数就没有问题
所以很多人推荐尽量用内联函数来代替这种预处理
而用const来代替那些预处理的常量定义
但是预处理也有很多inline实现不了的功能,看一下MFC中大量的宏就可以看到它强大的功能。

2, 内联函数是什么?



定义:
内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质。内联函数不是在调用时发生控制转移,而是在编译时将函数体嵌入在每一个调用处。编译时,类似宏替换,使用函数体替换调用处的函数名。一般在代码中用inline修饰,但是能否形成内联函数,需要看编译器对该函数定义的具体处理。
简介:
“一个函数声明[。。。]说明符声明一个内联与内联函数。内联说明符指示的实现,内联函数体替代了在调用点是首选通常的函数调用机制。一个实现不要求在调用执行此点内联替代,但是,即使这个内嵌替代省略,由7.1.2内联函数定义的其他规则,仍应得到尊重“。
注意事项:
内联函数具有一般函数的特性,它与一般函数所不同之处只在于函数调用的处理。一般函数进行调用时,要将程序执行权转到被调用函数中,然后再返回到调用它的函数中;而内联函数在调用时,是将调用表达式用内联函数体来替换。在使用内联函数时,应注意如下几点:
1. 在内联函数内不允许用循环语句和开关语句。 如果内联函数有这些语句,则编译将该函数视同普通函数那样产生函数调用代码,递归函数(自己调用自己的函数)是不能被用来做内联函数的。内联函数只适合于只有1~5行的小函数。对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,所以也没有必要用内联函数实现。
2. 内联函数的定义必须出现在内联函数第一次被调用之前。
3. 本栏目讲到的类结构中所有在类说明内部定义的函数是内联函数。

3, 内联函数是作什么用的?



普通函数在调用的时候,会经过
压栈
跳转
运行
弹栈
这几步操作,其中压栈,跳转,弹栈都增加了额外的开销。
而内联函数的函数体直接在调用的地方展开,省去了上面这三步。
如果你的函数体语句不多,并且会频繁的被调用,那么就用内联吧。
从内联的展开特性上来看,它与宏定义很相似,除此之外它还提供了宏定义锁没有的类型检查,可以带返回值以及方便调试的特性。

5, 什么是内联函数



楼主有意思,我觉得楼上的答案已经够“官方”的了么...
内联函数就是小型函数,牺牲空间来节省函数调用的开销,一般用作比较小的函数,即函数内部没有循环、开关语句等。内联函数被发明出来就是为了取代C中的宏,因为宏是单纯的替换而没有类型检查所以经常出毛病,比如:
#define MAX(a, b) (a) > (b) ? (a) : (b)
如果你在代码中这样写:
int a = 5, b = 10;
// int max = MAX(++a, b); // a自增了两次
// int max = MAX(++a, b+10); // a自增了一次
a的自增次数竟然由与其比较的数字的大小来决定!?这肯定不是你想要的结果。
所以最好的办法是这样:
template <class T>
inline T max(const T& t1, const T& t2)
{
return t1 > t2 ? t1 : t2;
}
这样的话如果你这样写:
int max = max(a, b);
其实就被替换为了:
int max = a > b ? a : b;
虽然看起来宏差不多,但是比宏多了类型检查,而且内联函数使用的是真正的函数的特性,而不是宏的function-like,模拟函数的功用。
内联函数是为频繁使用、并且过程不大的小型函数设计的,我说了它是以牺牲代码空间来节省函数调用的开销,内联函数使用不当就会造成代码膨胀,所以使用它一定要小心。
建议(书上抄的):
For function-like macros, prefer inline functions to #defines.
楼主有时间还是多看看书好,这里毕竟专家不多,而且也没多少人有太多的时间和精力来帮你解决这些基础性的问题,好好地读几本书吧,一定会让你获益匪浅的...

6, 内联函数与普通函数的区别是什么



内联函数是代码被插入到调用者代码处的函数。如同 #define 宏,内联函数通过避免被调用的开销来提高执行效率,尤其是它能够通过调用(“过程化集成”)被编译器优化。
内联函数和宏很类似,而区别在于,宏是由预处理器对宏进行替代,而内联函数是通过编译器控制来实现的。而且内联函数是真正的函数,只是在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开销。你可以象调用函数一样来调用内联函数,而不必担心会产生于处理宏的一些问题。
声明内联函数看上去和普通函数非常相似:
void f(int i, char c);
当你定义一个内联函数时,在函数定义前加上 inline 关键字,并且将定义放入头文件:
inline void f(int i, char c) { // ... }
任何在类的说明部分定义的函数都会被自动的认为是内联函数。
内联函数必须是和函数体申明在一起,才有效。像这样的申明Inline Tablefunction(int I)是没有效果的,编译器只是把函数作为普通的函数申明,我们必须定义函数体。
Inline tablefunction(int I) {return I*I};
这样我们才算定义了一个内联函数。我们可以把它作为一般的函数一样调用。但是执行速度确比一般函数的执行速度要快。
我们也可以将定义在类的外部的函数定义为内联函数,比如:
Class TableClass{ Private: Int I,j; Public: Int add() { return I+j;}; Inline int dec() { return I-j;} Int GetNum(); } inline int tableclass::GetNum(){ return I; }
上面申明的三个函数都是内联函数。在C++中,在类的内部定义了函数体的函数,被默认为是内联函数。而不管你是否有inline关键字。
内联函数在C++类中,应用最广的,应该是用来定义存取函数。我们定义的类中一般会把数据成员定义成私有的或者保护的,这样,外界就不能直接读写我们类成员的数据了。对于私有或者保护成员的读写就必须使用成员接口函数来进行。如果我们把这些读写成员函数定义成内联函数的话,将会获得比较好的效率。
Class sample{ Private: Int nTest; Public: Int readtest(){ return nTest;} Void settest(int I) {nTest=I;} }
当然,内联函数也有一定的局限性。就是函数中的执行代码不能太多了,如果,内联函数的函数体过大,一般的编译器会放弃内联方式,而采用普通的方式调用函数。这样,内联函数就和普通函数执行效率一样了。

相关概念


预处理

预处理(pre-treatment),是指在进行最后加工完善以前进行的准备过程,具体应用在不同的行业或领域,会有不同的解释。在一些程序设计语言中,预处理是preprocessing的翻译。

++

"++"是C和C++里的自增运算符,使可变左值(如变量,迭代器变量等)加一。 用法主要有两种: i++ ++i