c语言内联函数例子,【C++】 6_内联函数分析

常量与宏

C++ 中的 const 常量可以替代宏常数定义

const int A; <==> #define A 3

C++ 中是否有解决方案替代宏代码片段呢?

内联函数

C++ 中推荐使用内联函数替代宏代码片段

C++ 中使用 inline 关键字声明内联函数

inline int func(int a, int b)

{

return a < b ? a : b;

}

内联函数声明时 inline 关键字必须和函数定义结合在一起,否则编译器会直接忽略内联请求。

C++ 编译器可以将一个函数进行内联

被 C++ 编译器内联编译的函数叫做内联函数

C++ 编译器直接将函数体插入到函数调用的地方

内联函数没有普通函数调用时的额外开销(压栈,跳转,返回)

C++ 编译器不一定满足函数的内联请求!

编程实验: 内联函数初探

#include

#define FUNC(a, b) ((a) < (b) ? (a) : (b))

inline int func(int a, int b)

{

return a < b ? a : b;

}

void code_1()

{

int a = 1;

int b = 3;

int c = FUNC(++a, b);

printf("\ncode_1: \n");

printf("a = %d\n", a);

printf("b = %d\n", b);

printf("c = %d\n", c);

}

void code_2()

{

int a = 1;

int b = 3;

int c = func(++a, b);

printf("\ncode_2: \n");

printf("a = %d\n", a);

printf("b = %d\n", b);

printf("c = %d\n", c);

}

int main(int arc, char* argv[])

{

code_1();

code_2();

return 0;

}

输出:

code_1:

a = 3

b = 3

c = 3

code_2:

a = 2

b = 3

c = 2

分析: 【宏无法避免的副作用】

int c = FUNC(++a, b);

==>

int = ((++a) < (b) ? (++a) : (b))

内联函数具有普通函数的特征(参数检查,返回类型等)

函数的内联请求可能被编译器拒绝

函数被内联编译后,函数体直接扩展到调用的地方

宏代码片段由预处理器处理,进行简单的文本替换,没有任何编译过程,因此可能出现副作用。

现代 C++ 编译器能够进行编译优化,一些函数即使没有 inline 声明,也可能被内联编译

一些现代 C++ 编译器提供了扩展语法,能够对函数进行强制内联(这降低了可移植行)

g++: __attribute__((always_inline))

MSVC: __foreinline

编程实验: 内联函数深度示例

#include

// __forceinline

// __attribute__((always_inline))

inline

int add_inline(int n);

int main(int argc, char* argv[])

{

int r = add_inline(10);

printf("r = %d\n", r);

return 0;

}

inline int add_inline(int n)

{

int ret = 0;

for(int i=0; i

{

ret += i;

}

return n;

}

内联函数扩展选项默认,未强制内联时

VC2010 汇编:【内联请求失败】

int r = add_inline(10);

010E13AE push 0Ah

010E13B0 call add_inline (10E104Bh) ; 发生函数调用

010E13B5 add esp,4

010E13B8 mov dword ptr [r],eax

g++ 汇编 【内联请求失败】

main(int, char**):

08048494: push %ebp

08048495: mov %esp,%ebp

08048497: and $0xfffffff0,%esp

0804849a: sub $0x20,%esp

0804849d: movl $0xa,(%esp)

080484a4: call 0x80484c8 ; 发生函数调用

080484a9: mov %eax,0x1c(%esp)

080484ad: mov 0x1c(%esp),%eax

080484b1: mov %eax,0x4(%esp)

080484b5: movl $0x80485c0,(%esp)

080484bc: call 0x80483c0

080484c1: mov $0x0,%eax

080484c6: leave

080484c7: ret

内联函数扩展选项默认,强制内联时

VC2010 汇编:【内联请求成功】

int r = add_inline(10);

008C102C mov dword ptr [ebp-8],0

008C1033 mov dword ptr [ebp-0Ch],0

008C103A jmp wmain+35h (8C1045h)

008C103C mov eax,dword ptr [ebp-0Ch]

008C103F add eax,1

008C1042 mov dword ptr [ebp-0Ch],eax

008C1045 cmp dword ptr [ebp-0Ch],0Ah

008C1049 jge wmain+46h (8C1056h)

008C104B mov ecx,dword ptr [ebp-8]

008C104E add ecx,dword ptr [ebp-0Ch]

008C1051 mov dword ptr [ebp-8],ecx

008C1054 jmp wmain+2Ch (8C103Ch)

008C1056 mov edx,dword ptr [ebp-8]

008C1059 mov dword ptr [r],edx

g++ 汇编 【内联请求成功】

main(int, char**):

08048494: push %ebp

08048495: mov %esp,%ebp

08048497: and $0xfffffff0,%esp

0804849a: sub $0x20,%esp

9 {

0804849d: movl $0xa,0x18(%esp)

19 int ret = 0;

080484a5: movl $0x0,0x14(%esp)

21 for(int i=0; i

080484ad: movl $0x0,0x10(%esp)

080484b5: jmp 0x80484c4

23 ret += i;

080484b7: mov 0x10(%esp),%eax

080484bb: add %eax,0x14(%esp)

21 for(int i=0; i

080484bf: addl $0x1,0x10(%esp)

080484c4: mov 0x18(%esp),%eax

080484c8: cmp 0x10(%esp),%eax

080484cc: setg %al

080484cf: test %al,%al

080484d1: jne 0x80484b7

26 return ret;

080484d3: mov 0x14(%esp),%eax

10 int r = add_inline(10);

080484d7: mov %eax,0x1c(%esp)

12 printf(" r = %d\n", r);

080484db: mov 0x1c(%esp),%eax

080484df: mov %eax,0x4(%esp)

080484e3: movl $0x80485c0,(%esp)

080484ea: call 0x80483c0

14 return 0;

080484ef: mov $0x0,%eax

15 }

注意事项

C++ 中 inline 内联编译的限制(现在编译器基本都可满足内联要求,以下针对旧编译器而言)

不能存在任何形式的循环语句

不能存在过多的条件判断语句

函数体不能过于复杂

不能对函数进行取址操作

函数内联声明必须在调用语句之前

小结

C++ 中可以通过 inline 声明内联函数

编译器直接将内联函数扩展到函数调用的地方

inline 只是一种请求,编译器不一定允许这种请求

内联函数省去了函数调用时压栈,跳转和返回的开销

以上内容参考狄泰软件学院系列课程,请大家保护原创!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值