工业和信息化部网站备案管理系统,网站服务器建设的三种方法是什么,wordpress 商城站下载,网站开发语言学习C 吗1.inline 函数简介inline 函数由 inline 关键字定义#xff0c;引入 inline 函数的主要原因是用它替代 C 中复杂易错不易维护的宏函数。2.编译器对 inline 函数的处理办法编译器在编译阶段完成对 inline 函数的处理#xff0c;即对 inline 函数的调用替换为函数的本体。但 in… 1.inline 函数简介inline 函数由 inline 关键字定义引入 inline 函数的主要原因是用它替代 C 中复杂易错不易维护的宏函数。2.编译器对 inline 函数的处理办法编译器在编译阶段完成对 inline 函数的处理即对 inline 函数的调用替换为函数的本体。但 inline 关键字对编译器只是一种建议编译器可以这样去做也可以不去做。从逻辑上来说编译器对 inline 函数的处理步骤一般如下1将 inline 函数体复制到inline函数调用处2为所用 inline 函数中的局部变量分配内存空间3将 inline 函数的的输入参数和返回值映射到调用方法的局部变量空间中4如果 inline 函数有多个返回点将其转变为 inline 函数代码块末尾的分支使用GOTO。比如如下代码//求0-9的平方
inline int inlineFunc(int num)
{ if(num9||num0)return -1; return num*num;
} int main(int argc,char* argv[])
{int a8;int resinlineFunc(a);coutres:resendl;
}inline 之后的 main 函数代码类似于如下形式int main(int argc,char* argv[])
{int a8;{ int _temp_b8; int _temp; if (_temp_q 9||_temp_q0) _temp -1; else _temp _temp*_temp; b _temp; }
} 经过以上处理可消除所有与调用相关的痕迹以及性能的损失。inline 通过消除调用开销来提升性能。3.inline 函数使用的一般方法函数定义时在返回类型前加上关键字 inline 即把函数指定为内联函数申明时可加也可不加。但是建议函数申明的时候也加上 inline这样能够达到代码即注释的作用。使用格式如下inline int functionName(int first, int secend,...) {/****/};inline如果只修饰函数的申明的部分如下风格的函数foo不能成为内联函数inline void foo(int x, int y); //inline仅与函数声明放在一起void foo(int x, int y){}而如下风格的函数foo 则成为内联函数void foo(int x, int y);inline void foo(int x, int y){} //inline与函数定义体放在一起4.inline 函数的优点与缺点从上面可以知道inline函数相对宏函数有如下优点1内联函数同宏函数一样将在被调用处进行代码展开省去了参数压栈、栈帧开辟与回收结果返回等从而提高程序运行速度。2内联函数相比宏函数来说在代码展开时会做安全检查或自动类型转换同普通函数而宏定义则不会。例如宏函数和内联函数//宏函数
#define MAX(ab) ((a)(b)?(a):(b))//内联函数
inline int MAX(int aint b)
{return ab?a:b
}使用宏函数时其书写语法也较为苛刻如果对宏函数出现如下错误的调用MAX(a,Hello) 宏函数会错误地比较int和字符串没有参数类型检查但是使用内联函数的时候会出现类型不匹配的编译错误。3在类中声明同时定义的成员函数自动转化为内联函数因此内联函数可以访问类的成员变量宏定义则不能。4内联函数在运行时可调试而宏定义不可以。万事万物都有阴阳两面内联函数也不外乎如此使用inline函数也要三思慎重。inline函数的缺点总结如下1代码膨胀。inline函数带来的运行效率是典型的以空间换时间的做法。内联是以代码膨胀复制为代价消除函数调用带来的开销。如果执行函数体内代码的时间相比于函数调用的开销较大那么效率的收获会很少。另一方面每一处内联函数的调用都要复制代码将使程序的总代码量增大消耗更多的内存空间。2inline 函数无法随着函数库升级而升级。如果f是函数库中的一个inline函数使用它的用户会将f函数实体编译到他们的程序中。一旦函数库实现者改变f所有用到f的程序都必须重新编译。如果f是non-inline的用户程序只需重新连接即可。如果函数库采用的是动态连接那这一升级的f函数可以不知不觉的被程序使用。3是否内联程序员不可控。inline函数只是对编译器的建议是否对函数内联决定权在于编译器。编译器认为调用某函数的开销相对该函数本身的开销而言微不足道或者不足以为之承担代码膨胀的后果则没必要内联该函数若函数出现递归有些编译器则不支持将其内联。5.inline函数的注意事项了解了内联函数的优缺点在使用内联函数时我们也要注意以下几个事项和建议。1使用函数指针调用内联函数将会导致内联失败。也就是说如果使用函数指针来调用内联函数那么就需要获取inline函数的地址。如果要取得一个inline函数的地址编译器就必须为此函数产生一个函数实体那么就内联失败。2如果函数体代码过长或者有多重循环语句if或witch分支语句或递归时不宜用内联。3类的 constructors、destructors 和虚函数往往不是 inline 函数的最佳选择。类的构造函数constructors可能需要调用父类的构造函数析构函数同样可能需要调用父类的析构函数二者背后隐藏着大量的代码不适合作为inline函数。虚函数destructors往往是运行时确定的而inline是在编译时进行的所以内联虚函数往往无效。如果直接用类的对象来使用虚函数那么对有的编译器而言也可起到优化作用。4至于内联函数是定义在头文件还是源文件的建议。内联展开是在编译时进行的只有链接的时候源文件之间才有关系。所以内联要想跨源文件必须把实现写在头文件里。如果一个 inline 函数会在多个源文件中被用到那么必须把它定义在头文件中。// base.h
class base{protected:void fun();};// base.cpp
#include base.h
inline void base::fun(){}//derived.h
#include base.h
class Derived: public base{public:void g();};// derived.cpp
void Derived::g(){fun();} //VC2010: error LNK2019: unresolved external symbol上面这种错误就是因为内联函数 fun() 定义在编译单元 base.cpp 中那么其他编译单元中调用fun()的地方将无法解析该符号因为在编译单元 base.cpp 生成目标文件 base.obj 后内联函数fun()已经被替换掉编译器不会为 fun() 生成函数实体链接器自然无法解析。所以如果一个 inline 函数会在多个源文件中被用到那么必须把它定义在头文件中。这里有个问题当在头文件中定义内联函数那么被多个源文件包含时如果编译器因为 inline 函数不适合被内联时拒绝将inline函数进行内联处理那么多个源文件在编译生成目标文件后都将各自保留一份inline函数的实体这个时候程序在链接阶段会出现重定义错误吗答案是不会原因是链接器在链接的过程中会删除多余的inline函数实体只保留一份所以不会报重定义错误因此我们不需要使用 static 关键字去多余地修饰inline函数即不必像下面这样。//test.h
static inline int max(int a,int b)
{return ab?a:b;
}5能否强制编译器进行内联操作也有人可能会觉得能否强制编译器进行函数内联而不是建议编译器进行内联呢很不幸的是目前还不能强制编译器进行函数内联如果使用的是 MS VC, 注意 __forceinline 如同 inine 一样也是一个用词不当的表现它只是对编译器的建议比inline更加强烈并不能强制编译器进行inline操作。6如何查看函数是否被内联处理了在 VS2017 中查看预处理后的.i文件发现inline函数的内联处理不是在预处理阶段而是在编译阶段。将源文件编译为汇编代码或者将可执行文件反汇编生成汇编代码在汇编代码中查看inline函数被调用处是否出现汇编的call指令如果没有则说明inline函数在被调用处进行了函数体的替换操作即内联处理。具体可以参考内联函数到底有没有被嵌入到调用处呢。7C类成员函数定义在类体内为什么不会报重定义错误类成员函数定义在类体内并随着类的定义放在头文件中当被不同的源文件包含那么每个源文件都应该包含了类成员函数的实体为何在链接的过程中不会报函数的重定义错误呢原因是在类里定义时这种函数会被编译器编译成内联函数在类外定义的函数则不会。内联函数的好处是加快程序的运行速度缺点是会增加程序的尺寸。比较推荐的写法是把一个经常要用的而且实现起来比较简单的小型函数放到类里去定义大型函数最好还是放到类外定义。可能存在疑问类体内的成员函数被编译器内联处理但并不是所有的成员函数都会被内联处理比如包含递归的成员函数。但是实际测试将包含递归的成员函数定义在类体内被不同的源文件包含并不会报重定义错误为什么会这样呢请保持着疑问与好奇心请继续往下看。如果编译器发现被定义在类体内的成员函数无法被内联处理那么在程序的链接过程中也不会出现函数重定义的错误。其原因是什么呢其实很简单类体内定义的成员函数即使不被内联处理在链接时链接器会对重复的成员函数实体进行冗余优化只保留一份函数实体也就不会出现函数重定义的错误了。除了 inline 函数C编译器在很多时候都会产生重复的代码比如模板Templates、虚函数表Virtual Function Table、类的默认成员函数构造函数、析构函数和赋值运算符等。以函数模板为例在多个源文件中生成相同的实例链接时不会出现函数重定义的错误实际上是一个道理因为链接器会对重复代码进行删除只保留一份函数实体。6.小结可以将内联理解为 C 中对于函数专有的宏对于 C 的函数宏的一种改进。对于常量宏C 提供 const 替代而对于函数宏C 提供的方案则是 inline。C 的内联机制既具备宏代码的效率又增加了安全性还可以自由操作类的数据成员算是一个比较完美的解决方案。来源https://dablelv.blog.csdn.net/article/details/52065524