关于宏和内联函数

宏:

1.在C程序中,可以用宏代码提高执行效率。宏代码本身不是函数,但是用起来像函数。编译预处理器用拷贝宏代码的方式取代函数调用,省去了参数压栈、生成汇编语言最大的缺点就是容易出错,预处理器在拷贝宏代码时常常产生意想不到的边际效应。

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

result = Max(i,j)+2;
//扩展为
result = (i)>(j):(i):(j)+2;

由于运算符'+'比运算符'?:'优先级高,所以以上宏定义不符合期望要求
必须改成 #define Max(a,b)  ((a)>(b) ? (a):(b))

另外result = Max(i++,j); 
//扩展为
result = (i++)>(j):(i++):(j);

//同一个表达式i被两次求值 


2.宏的另一个缺点就是不可调试,但是内联函数可以调试。

3.C++中引入了类及类的访问控制,使用宏无法操作类的私有数据成员也无法操作或者说一个表达式涉及类的保护成员以及私有成员(因为无法将this指针放在合适的位置)。

内联函数

核心:只有当函数只有 10 行甚至更少时才将其定义为内联函数.

定义: 当函数被声明为内联函数之后, 编译器会将其内联展开, 而不是按通常的函数调用机制进行调用.

优点: 当函数体比较小的时候, 内联该函数可以令目标代码更加高效. 对于存取函数以及其它函数体比较短, 性能关键的函数, 鼓励使用内联.

缺点: 滥用内联将导致程序变慢. 内联可能使目标代码量或增或减, 这取决于内联函数的大小. 内联非常短小的存取函数通常会减少代码大小, 但内联一个相当大的函数将戏剧性的增加代码大小. 现代处理器由于更好的利用了指令缓存, 小巧的代码往往执行更快。

结论: 一个较为合理的经验准则是, 不要内联超过 10 行的函数. 谨慎对待析构函数, 析构函数往往比其表面看起来要更长, 因为有隐含的成员和基类析构函数被调用!

另一个实用的经验准则: 内联那些包含循环或 switch 语句的函数常常是得不偿失 (除非在大多数情况下, 这些循环或 switch 语句从不被执行).

有些函数即使声明为内联的也不一定会被编译器内联, 这点很重要; 比如虚函数和递归函数就不会被正常内联. 通常, 递归函数不应该声明成内联函数.(递归调用堆栈的展开并不像循环那么简单, 比如递归层数在编译时可能是未知的, 大多数编译器都不支持内联递归函数). 虚函数内联的主要原因则是想把它的函数体放在类定义内, 为了图个方便, 抑或是当作文档描述其行为, 比如精短的存取函数.

关于内联函数涉及了编译器的符号表。对任何内联函数,编译器在符号表里放入函数的声明,包括名字、参数类型、返回值类型(符号表是编译器用来收集和保存字面变量和某些符号常量的地方)。如果编译器没有发现错误,该函数的代码也将被放入符号表里。使用时,编译器检查调用是否正确,如果正确,内联函数的代码就会直接替换函数调用语句,于是省去了函数调用的开销(普通函数调用时会生成一份拷贝)。这个过程与预处理器有显著的不同,因为预处理器不能进行类型安全检查和自动类型转换。加入内联函数是成员函数,对象的地址(this)会被放在合适的地方。

因此在C++中除了断言assert,都应该使用内联函数替换宏代码。如果函数被内联,编译器就可以通过上下文相关的优化技术对结果代码执行更深入的优化。这种优化在普通函数体内是无法单独进行的,因为一旦进入函数体内它也就脱离了调用环境的上下文。

关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用。

内联函数应该在头文件中定义,这一点不同于其他函数。编译器在调用点内联展开函数的代码时,必须能够找到 inline 函数的定义才能将调用函数替换为函数代码,而对于在头文件中仅有函数声明是不够的。
当然内联函数定义也可以放在源文件中,但此时只有定义的那个源文件可以用它,而且必须为每个源文件拷贝一份定义(即每个源文件里的定义必须是完全相同的),当然即使是放在头文件中,也是对每个定义做一份拷贝,只不过是编译器替你完成这种拷贝罢了。但相比于放在源文件中,放在头文件中既能够确保调用函数是定义是相同的,又能够保证在调用点能够找到函数定义从而完成内联(替换)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值