用汇编来看看inline

inline说明

  inline关键字仅仅是建议编译器做内联展开处理,而不是强制。在gcc编译器中,如果编译优化设置为O0,即使是inline函数也不会被内联展开,除非设置了强制内联(__attribute__((always_inline)))属性。对于可展开与必须当成函数的情形同时出现,则在展开处需展开,在当成函数调用处则当函数处理.

有下面几个文件

test.h ,test6.c,test7.c 

test.h

inline   int fun(int i){
	return i+1;
}
test6.c

#include "test.h"
int main(){
	int i=0;
//	for(;i>-1;)
	i = fun(89);
	return 0;
}
test7.c

inline int fun(int i){
	i = 15;
	return i+1;
}

1.1. static inline

  gcc的static inline相对于static函数来说只是在调用时建议编译器进行内联展开;gcc不会特意为static inline函数生成独立的汇编码,除非出现了必须生成不可的情况(例如函数指针调用和递归调用);
I)不展开
    函数本身递归等;函数的地址被使用时(赋予函数指针)
II)展开
    gcc会在其调用处将其汇编码展开编译而不为这个函数生成独立的汇编码.

测试:

在a.h中函数名前加static 

static inline   int fun(int i) ;

$ gcc test6.c -S -o a.o

$ vi a.o

        .file   "test6.c"
        .text
.globl fun
        .type   fun, @function
fun:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        addl    $1, %eax
        popl    %ebp
        ret
        .size   fun, .-fun
.globl main
        .type   main, @function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $20, %esp
        movl    $0, -4(%ebp)
        movl    $89, (%esp)
        call    fun
        movl    %eax, -4(%ebp)
        movl    $0, %eax
        leave
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 4.4.6 20120305 (Red Hat 4.4.6-4)"
        .section        .note.GNU-stack,"",@progbits

你把份汇编代码与不加任何inline进行对比,发现,一模一样!!!!看来没有建议成功    

1.2. inline

     gcc的inline更容易理解:可以认为它是一个普通的全局函数加上了inline的属性。即在其定义所在文件内,它的行为和static inline一致:在能展开的时候会被内联展开编译。但是为了能够在文件外调用它,gcc一定会为它生成一份独立的汇编码,以便在外部进行调用。


  gcc的inline函数相对于普通的extern函数来说只是在同一个文件内调用时建议编译器进行内联展开;gcc一定回为inline函数生成一份独立的汇编码以供外部文件调用。在其它文件看来,这个inline函数和普通的extern函数无异;gcc的inline函数是全局性的:在文件内可以作为一个内联函数被内联展开,而在文件外可以调用它。
    gcc的static inline和inline比较容易理解,可以认为是对普通函数添加可内联的属性。

测试:

发现编译出来的汇编代码与上面的一样

1.3. extern inline

    gcc的extern inline十分古怪:一个extern inline函数只会被内联,而绝不会生成独立的汇编码!!!如果某处必须将其当成普通的函数,则此时对此函数的调用会被处理成一个外部引用。此外,extern inline 的函数允许和外部函数重名,即在存在一个外部定义的全局库函数的情况下,再定义一个同名的extern inline函数也是合法的。

测试 :

将test.h改成:

extern inline   int fun(int i){
	return i+1;
}

$gcc test6.c test7.c -S

$vi test6.s

        .file   "test6.c"
        .text
.globl main
        .type   main, @function
main:
        pushl   %ebp
        movl    %esp, %ebp
        andl    $-16, %esp
        subl    $32, %esp
        movl    $0, 28(%esp)
        movl    $89, (%esp)
        call    fun
        movl    %eax, 28(%esp)
        movl    $0, %eax
        leave
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 4.4.6 20120305 (Red Hat 4.4.6-4)"
        .section        .note.GNU-stack,"",@progbits

可以发现没有生成fun的汇编代码,说明fun实际调用的test7.c中的代码,哪怕在test.h中有定义

gcc绝不会为extern inline的函数生成独立的汇编码;extern inline函数允许和全局函数重名,可以在文件范围内替代外部定义的全局函数;使用extern inline时必须给予文档注释!!!!


1.4 __attribute((always_inline))来进行强制内联

将a.h改成:

inline __attribute((always_inline)) int fun(int i){
       return i+1;
}

编译一下,再看看汇编代码:

        .file   "test6.c"
        .text
.globl fun
        .type   fun, @function
fun:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        addl    $1, %eax
        popl    %ebp
        ret
        .size   fun, .-fun
.globl main
        .type   main, @function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $16, %esp
        movl    $0, -8(%ebp)
        movl    $89, -4(%ebp)
        movl    -4(%ebp), %eax
        addl    $1, %eax
        movl    %eax, -8(%ebp)
        movl    $0, %eax
        leave
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 4.4.6 20120305 (Red Hat 4.4.6-4)"
        .section        .note.GNU-stack,"",@progbits


呵呵呵,发现了什么不同的没?

参考:http://www.cnblogs.com/openix/archive/2012/11/18/2775625.html

http://blog.csdn.net/baozi3026/article/details/5372268



你可能感兴趣的:(用汇编来看看inline)