内联函数并不总是内联

Inline function是在C++中引入的一种机制,它可以拓展函数代码,避免调用函数的额外开销。在Linux环境下,gcc编译选项必须加上优化选项才能使inline有效。如

 

inline int fun(int i, int j)

 

{

        printf("%d/n", i+j);

        return i+j;

}

 

void main()
{
fun(3,4);
}
不带优化编译选项:g++ -S inline.cc
产生的汇编代码片断如下:
andl    $-16, %esp    ;栈指针对齐
subl    $16, %esp     ; 栈指针下移,为函数调用参数预留足够空间
movl    $4, 4(%esp)  ;参数入栈,后声明先入
movl    $3, (%esp)    ;参数入栈,先声明后入
call    _Z3funii           ;函数调用,经过name-mangling处理
即使是inline函数,如果不带优化编译选项,inline关键字也不会对fun产生任何影响
那现在加上优化选项:g++ -S -O inline.cc
产生的汇编代码片断如下:
 andl    $-16, %esp
 subl    $16, %esp
 movl    $7, 4(%esp)
 movl    $.LC0, (%esp)
 call    printf
这里已经没有了函数调用的过程,fun函数已经被拓展了。
那现在有一个问题,是不是只要加上inline定义的函数,加上优化选项,就能一定被拓展呢?答案是否定的,因为,加上inline关键字,只是告诉编译器,函数想要被inline,但决定权在编译器手里,由它来决定函数是否inline。这是因为有的函数复杂度很高,这样的话,如果拓展就得不偿失,这样编译器就会忽略inline关键字,不会对函数调用做任何额外的处理,例如定义一个递归函数。还有一种情况是virtual函数,它既可以是内联函数,也可以不是内联函数。

inline int fun(int i, int j)

 

{

if(i-->0)

fun(i, j);

        printf("%d/n", i+j);

        return i+j;

}

 

那现在我们再来看看编译器是否会使函数inline:g++ -S -O inline.cc
产生的汇编代码片断如下:
main:
.LFB12:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp
        .cfi_def_cfa_register 5
        andl    $-16, %esp
        subl    $16, %esp
        movl    $4, 4(%esp)
        movl    $2, (%esp)
        call    _Z3funii
        movl    $6, 4(%esp)
        movl    $.LC0, (%esp)
        call    printf
        movl    $0, %eax
答案很清晰了。
对于virtual函数来说,如果没有触发它的virtual机制,那么,virtual函数是当作正常函数来调用的,这种情况下就可以使用内联机制,如果调用时触发了virtual机制(也就是通过指针或引用来调用),那么这个时候inline的虚函数是没法内联的。也就是说,只有当编译器在编译期能够确定的情况下,inline才能起作用,而触发了virtual机制的地方,调用的函数地址的可变的,没法把它用确定的函数代码替换,只能通过函数调用的方式来使用,所以没法使用inline。如:
class Base
{
public:
        virtual void vfun(int i) { printf("%p/n", i); }
};
int main()
{
        Base b;
        b.vfun(3);
        Base *bp = &b;
        bp->vfun(4);
return 0;
}
主要汇编代码如下:
andl    $-16, %esp
        subl    $32, %esp
//b.vfun(3); 使用内联
        movl    $_ZTV4Base+8, 28(%esp)
        movl    $3, 4(%esp)
        movl    $.LC0, (%esp)
        call    printf
//bp->vfun(4); 正常函数调用
        movl    $4, 4(%esp)
        leal    28(%esp), %eax
        movl    %eax, (%esp)
         call    _ZN4Base4vfunEi

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值