gcc之inline函数探究

来源:互联网 发布:串口通信软件破解 编辑:程序博客网 时间:2024/05/16 06:41

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