1、引子:内联函数(以下称为inline函数)的行为类似于宏,但是会像函数一样进行参数的静态类型检查。因此gcc中很多地方倾向于使用inline函数来替代宏。但是inline函数在gcc中应该如何使用呢?函数被内联之后究竟有哪些改变呢?
#include "stdio.h"
//inline int func(int a) __attribute__((always_inline)); // func有,内联成功puts
//inline int func(int a); // func有,未内联
//int func(int a) __attribute__((noinline)); // func有,未内联
//static inline int func(int a) __attribute__((always_inline)); // func无,内联成功puts
//static inline int func(int a); // func有,未内联
//static int func(int a) __attribute__((noinline)); // func有,未内联
//extern inline int func(int a) __attribute__((always_inline)); // func有,未内联
//extern inline int func(int a); // func有,未内联
//extern int func(int a) __attribute__((noinline)); // func有,未内联
int func(int a)
{
a += 5;
printf("inline test, a = %d\n", a);
}
int main(void)
{
func(5);
func(6);
func(7);
return 0;
}
2、测试方法:
测试代码如上,非常简单的一个函数func,func在主程序中被调用3次。我们分别使用上面三组、每组三个的声明方式来对func函数进行声明。然后使用gcc inline.c -o xx 来进行编译链接,生成可执行文件xx,然后用objdump xx -d > xx.txt来对刚才生成的可执行程序进行反汇编,得到对应的汇编代码。这里的xx在每种声明方式下不同,我采用组号+组内编号的形式来命名,如第一种声明方式xx为11,而最后一种声明方式中xx为33。
测试后查看反汇编代码xx.txt,重点关注两个问题:
2.1、func有无被内联处理?
2.2、func函数在最终的可执行程序中有没有生成独立代码段
3、结果分析:
3.1、实际的测试结果如9种声明之后标注的,即只有11和21这两种下func被内联处理,其他情况下都未内联。这是__attribute__((always_inline))产生的影响。比较有趣的是31也未被内联,尽管使用了强制内联,但是在extern inline下还是不进行内联处理,这也是跟网上查到的一些资料不符的地方。
3.2、21中func未生成独立代码段,而其他均有生成。这个很好理解,因为static声明的函数只会被该文本内引用而不会被外部引用,而inline之后该文本内所有对func的引用都被内联了,因此func没有必要再生成独立的代码段了。(程序中func本身不是递归函数,而且func未被赋值给某一函数指针)
4、反汇编代码很长很多,这里只贴出两组来。一是11,二是12。因为这两组可以代表其他的情况了。而且只贴出func和main两个函数相关的代码段:
-----------11.txt片段--------------------
080483e4 <func>:
80483e4: 55 push %ebp
80483e5: 89 e5 mov %esp,%ebp
80483e7: 83 ec 18 sub $0x18,%esp
80483ea: 83 45 08 05 addl $0x5,0x8(%ebp)
80483ee: b8 40 85 04 08 mov $0x8048540,%eax
80483f3: 8b 55 08 mov 0x8(%ebp),%edx
80483f6: 89 54 24 04 mov %edx,0x4(%esp)
80483fa: 89 04 24 mov %eax,(%esp)
80483fd: e8 1a ff ff ff call 804831c <printf@plt>
8048402: c9 leave
8048403: c3 ret
08048404 <main>:
8048404: 55 push %ebp
8048405: 89 e5 mov %esp,%ebp
8048407: 83 e4 f0 and $0xfffffff0,%esp
804840a: 83 ec 20 sub $0x20,%esp
804840d: c7 44 24 1c 05 00 00 movl $0x5,0x1c(%esp)
8048414: 00
8048415: 83 44 24 1c 05 addl $0x5,0x1c(%esp)
804841a: b8 40 85 04 08 mov $0x8048540,%eax
804841f: 8b 54 24 1c mov 0x1c(%esp),%edx
8048423: 89 54 24 04 mov %edx,0x4(%esp)
8048427: 89 04 24 mov %eax,(%esp)
804842a: e8 ed fe ff ff call 804831c <printf@plt>
804842f: c7 44 24 18 06 00 00 movl $0x6,0x18(%esp)
8048436: 00
8048437: 83 44 24 18 05 addl $0x5,0x18(%esp)
804843c: b8 40 85 04 08 mov $0x8048540,%eax
8048441: 8b 54 24 18 mov 0x18(%esp),%edx
8048445: 89 54 24 04 mov %edx,0x4(%esp)
8048449: 89 04 24 mov %eax,(%esp)
804844c: e8 cb fe ff ff call 804831c <printf@plt>
8048451: c7 44 24 14 07 00 00 movl $0x7,0x14(%esp)
8048458: 00
8048459: 83 44 24 14 05 addl $0x5,0x14(%esp)
804845e: b8 40 85 04 08 mov $0x8048540,%eax
8048463: 8b 54 24 14 mov 0x14(%esp),%edx
8048467: 89 54 24 04 mov %edx,0x4(%esp)
804846b: 89 04 24 mov %eax,(%esp)
804846e: e8 a9 fe ff ff call 804831c <printf@plt>
8048473: b8 00 00 00 00 mov $0x0,%eax
8048478: c9 leave
8048479: c3 ret
804847a: 90 nop
804847b: 90 nop
804847c: 90 nop
804847d: 90 nop
804847e: 90 nop
804847f: 90 nop
----------12.txt片段----------------------
080483e4 <func>:
80483e4: 55 push %ebp
80483e5: 89 e5 mov %esp,%ebp
80483e7: 83 ec 18 sub $0x18,%esp
80483ea: 83 45 08 05 addl $0x5,0x8(%ebp)
80483ee: b8 00 85 04 08 mov $0x8048500,%eax
80483f3: 8b 55 08 mov 0x8(%ebp),%edx
80483f6: 89 54 24 04 mov %edx,0x4(%esp)
80483fa: 89 04 24 mov %eax,(%esp)
80483fd: e8 1a ff ff ff call 804831c <printf@plt>
8048402: c9 leave
8048403: c3 ret
08048404 <main>:
8048404: 55 push %ebp
8048405: 89 e5 mov %esp,%ebp
8048407: 83 e4 f0 and $0xfffffff0,%esp
804840a: 83 ec 10 sub $0x10,%esp
804840d: c7 04 24 05 00 00 00 movl $0x5,(%esp)
8048414: e8 cb ff ff ff call 80483e4 <func>
8048419: c7 04 24 06 00 00 00 movl $0x6,(%esp)
8048420: e8 bf ff ff ff call 80483e4 <func>
8048425: c7 04 24 07 00 00 00 movl $0x7,(%esp)
804842c: e8 b3 ff ff ff call 80483e4 <func>
8048431: b8 00 00 00 00 mov $0x0,%eax
8048436: c9 leave
8048437: c3 ret
8048438: 90 nop
8048439: 90 nop
804843a: 90 nop
804843b: 90 nop
804843c: 90 nop
804843d: 90 nop
804843e: 90 nop
804843f: 90 nop