免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 3229 | 回复: 16
打印 上一主题 下一主题

[内核入门] 关于内联函数inline [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2016-04-28 10:10 |只看该作者 |倒序浏览
本帖最后由 allkillers 于 2016-04-28 10:12 编辑

一直看书上说内联函数是通过在使用时直接替换,没有了调用的开销,从而执行效率很高。字面意思可以理解,但具体是怎么反映出执行效率高的,真没看出来。,如下分两种情况进行汇编对比,如下:

第一种,inline函数:
static inline void test(int i, int j)
{
}

int main(void)
{
    test(1,5);
    return 0;
}

汇编为:

00000000004004ed <test>:
  4004ed:       55                      push   %rbp
  4004ee:       48 89 e5                mov    %rsp,%rbp
  4004f1:       89 7d fc                mov    %edi,-0x4(%rbp)
  4004f4:       89 75 f8                mov    %esi,-0x8(%rbp)
  4004f7:       5d                      pop    %rbp
  4004f8:       c3                      retq

00000000004004f9 <main>:
  4004f9:       55                      push   %rbp
  4004fa:       48 89 e5                mov    %rsp,%rbp
  4004fd:       be 05 00 00 00          mov    $0x5,%esi
  400502:       bf 01 00 00 00          mov    $0x1,%edi
  400507:       e8 e1 ff ff ff          callq  4004ed <test>
  40050c:       b8 00 00 00 00          mov    $0x0,%eax
  400511:       5d                      pop    %rbp
  400512:       c3                      retq
  400513:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  40051a:       00 00 00
  40051d:       0f 1f 00                nopl   (%rax)


第二种,普通函数:
static void test(int i, int j)
{
}

int main(void)
{
    test(1,5);
    return 0;
}
汇编为:
00000000004004ed <test>:
  4004ed:       55                      push   %rbp
  4004ee:       48 89 e5                mov    %rsp,%rbp
  4004f1:       89 7d fc                mov    %edi,-0x4(%rbp)
  4004f4:       89 75 f8                mov    %esi,-0x8(%rbp)
  4004f7:       5d                      pop    %rbp
  4004f8:       c3                      retq

00000000004004f9 <main>:
  4004f9:       55                      push   %rbp
  4004fa:       48 89 e5                mov    %rsp,%rbp
  4004fd:       be 05 00 00 00          mov    $0x5,%esi
  400502:       bf 01 00 00 00          mov    $0x1,%edi
  400507:       e8 e1 ff ff ff          callq  4004ed <test>
  40050c:       b8 00 00 00 00          mov    $0x0,%eax
  400511:       5d                      pop    %rbp
  400512:       c3                      retq
  400513:       66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  40051a:       00 00 00
  40051d:       0f 1f 00                nopl   (%rax)


结论:

从汇编来看并无区别,并没有“内联”的动作,还是普通的函数调用啊,那究竟是怎么提高效率的?求解。

评分

参与人数 1可用积分 +6 收起 理由
Godbach + 6 很有意义的讨论!

查看全部评分

论坛徽章:
9
程序设计版块每日发帖之星
日期:2016-02-11 06:20:00程序设计版块每日发帖之星
日期:2016-02-14 06:20:00程序设计版块每日发帖之星
日期:2016-02-14 06:20:0015-16赛季CBA联赛之吉林
日期:2016-03-23 17:25:0015-16赛季CBA联赛之浙江
日期:2016-04-01 08:25:0615-16赛季CBA联赛之山西
日期:2016-04-01 10:09:1915-16赛季CBA联赛之广夏
日期:2016-06-03 15:58:212016科比退役纪念章
日期:2016-07-28 17:42:5215-16赛季CBA联赛之广东
日期:2017-02-20 23:32:43
2 [报告]
发表于 2016-04-28 10:30 |只看该作者
回复 1# allkillers


    您可以去看一下“预处理”这个阶段,inline 的处理是在这个阶段,还没到汇编阶段
   

论坛徽章:
0
3 [报告]
发表于 2016-04-28 10:46 |只看该作者
预处理的处理结果更应该在汇编中体现才对啊,如果汇编中都没有体现,只能在运行期体现了,例如#define N (30) ,预处理的结果就是你可以在汇编中看到常量“30”。我的看法是,因为相同的汇编码必定会是相同的机器码,相同的机器码那就意味着执行序列及效率必然相同。不知道我的理解有没有问题。回复 2# Buddy_Zhang1


   

论坛徽章:
9
程序设计版块每日发帖之星
日期:2016-02-11 06:20:00程序设计版块每日发帖之星
日期:2016-02-14 06:20:00程序设计版块每日发帖之星
日期:2016-02-14 06:20:0015-16赛季CBA联赛之吉林
日期:2016-03-23 17:25:0015-16赛季CBA联赛之浙江
日期:2016-04-01 08:25:0615-16赛季CBA联赛之山西
日期:2016-04-01 10:09:1915-16赛季CBA联赛之广夏
日期:2016-06-03 15:58:212016科比退役纪念章
日期:2016-07-28 17:42:5215-16赛季CBA联赛之广东
日期:2017-02-20 23:32:43
4 [报告]
发表于 2016-04-28 10:55 |只看该作者
回复 3# allkillers

      你可以在您的 demo code 上使用下面命令来看预处理过程
      gcc xxx.c -E
   
      四个阶段:预处理-编译-汇编-链接
   

论坛徽章:
0
5 [报告]
发表于 2016-04-28 11:03 |只看该作者
好的,我再研究研究。但我贴出来的汇编代码已经是链接后的结果了,这一点应该是确定的。回复 4# Buddy_Zhang1


   

论坛徽章:
22
丑牛
日期:2014-08-15 14:32:0015-16赛季CBA联赛之同曦
日期:2017-12-14 15:28:14黑曼巴
日期:2017-08-10 08:14:342017金鸡报晓
日期:2017-02-08 10:39:42黑曼巴
日期:2016-11-15 15:48:38CU十四周年纪念徽章
日期:2016-11-09 13:19:1015-16赛季CBA联赛之同曦
日期:2016-04-08 18:00:03平安夜徽章
日期:2015-12-26 00:06:30程序设计版块每日发帖之星
日期:2015-12-03 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-09 06:20:002015亚冠之吉达阿赫利
日期:2015-07-03 08:39:42
6 [报告]
发表于 2016-04-28 11:06 |只看该作者
本帖最后由 amarant 于 2016-04-29 10:05 编辑

你没有加优化等级,默认不会内联。如果需要强行内联,需要按下面语法操作。
GCC does not inline any functions when not optimizing unless you specify the ‘always_inline’ attribute for the function, like this:

     /* Prototype.  */
     inline void foo (const char) __attribute__((always_inline));

参考
https://gcc.gnu.org/onlinedocs/gcc/Inline.html

论坛徽章:
0
7 [报告]
发表于 2016-04-28 14:19 |只看该作者
可以参见gcc源码中处理inline的两个相关pass,pass_early_inline和pass_ipa_inline,pass_early_inline在不指定优化选项-Onum时,只通过inline_always_inline_functions来内联指定了“always_inline”attribute的函数,pass_ipa_inine在不指定优化选项-Onum时直接返回不做任何inline处理

评分

参与人数 2可用积分 +10 信誉积分 +15 收起 理由
nswcfd + 5 学习了
amarant + 10 + 10 赞一个!

查看全部评分

论坛徽章:
11
程序设计版块每日发帖之星
日期:2015-09-09 06:20:00CU十四周年纪念徽章
日期:2016-05-16 11:11:112016科比退役纪念章
日期:2016-05-04 17:16:57程序设计版块每日发帖之星
日期:2016-02-20 06:20:00程序设计版块每周发帖之星
日期:2015-11-06 19:30:58程序设计版块每日发帖之星
日期:2015-09-12 06:20:00程序设计版块每日发帖之星
日期:2015-09-11 06:20:00每日论坛发贴之星
日期:2015-09-10 06:20:00程序设计版块每日发帖之星
日期:2015-09-10 06:20:00每日论坛发贴之星
日期:2015-09-09 06:20:0015-16赛季CBA联赛之四川
日期:2016-12-15 15:52:10
8 [报告]
发表于 2016-04-28 16:18 |只看该作者
按说内连函数是预处理阶段直接处理的,汇编中应该有函数调用保存现场的动作,是不是你的test函数太简单,编译器优化掉了呢?

论坛徽章:
13
15-16赛季CBA联赛之八一
日期:2016-07-08 21:00:1415-16赛季CBA联赛之同曦
日期:2017-02-15 14:26:1515-16赛季CBA联赛之佛山
日期:2017-02-20 14:19:2615-16赛季CBA联赛之青岛
日期:2017-05-07 16:49:1115-16赛季CBA联赛之广夏
日期:2017-07-30 09:13:1215-16赛季CBA联赛之广东
日期:2018-07-05 22:34:3615-16赛季CBA联赛之江苏
日期:2018-09-03 12:10:2115-16赛季CBA联赛之上海
日期:2018-09-25 03:49:2215-16赛季CBA联赛之广东
日期:2018-09-25 04:09:12
9 [报告]
发表于 2016-04-28 16:41 |只看该作者
回复 8# 我爱你我的菜

我第一反应也是优化级别,分别加-O0、-O1、-O2编译,看看有不有区别,内联函数不像宏函数,编译器“视情况”确定将其当作普通函数还是宏函数,“视情况”估计就是看优化级别是多少吧,没试过。

论坛徽章:
11
程序设计版块每日发帖之星
日期:2015-09-09 06:20:00CU十四周年纪念徽章
日期:2016-05-16 11:11:112016科比退役纪念章
日期:2016-05-04 17:16:57程序设计版块每日发帖之星
日期:2016-02-20 06:20:00程序设计版块每周发帖之星
日期:2015-11-06 19:30:58程序设计版块每日发帖之星
日期:2015-09-12 06:20:00程序设计版块每日发帖之星
日期:2015-09-11 06:20:00每日论坛发贴之星
日期:2015-09-10 06:20:00程序设计版块每日发帖之星
日期:2015-09-10 06:20:00每日论坛发贴之星
日期:2015-09-09 06:20:0015-16赛季CBA联赛之四川
日期:2016-12-15 15:52:10
10 [报告]
发表于 2016-04-28 16:50 |只看该作者
理解错了,上面是inline没有生效

生效代码:
#include<stdio.h>

inline  static  void test(int i, int j)__attribute__ ((always_inline));
static  void test(int i, int j)
{
        int sum;
        sum=i+j;
}

int main(void)
{
    test(1,5);
    return 0;
}

对比汇编:
        .file        "1.c"
        .text
        .type        test, @function
test:
.LFB0:
        .cfi_startproc
        pushl        %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl        %esp, %ebp
        .cfi_def_cfa_register 5
        subl        $16, %esp
        movl        12(%ebp), %eax
        movl        8(%ebp), %edx
        addl        %edx, %eax
        movl        %eax, -4(%ebp)
        leave
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
        .cfi_endproc
.LFE0:
        .size        test, .-test
        .globl        main
        .type        main, @function
main:
.LFB1:
        .cfi_startproc
        pushl        %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl        %esp, %ebp
        .cfi_def_cfa_register 5
        subl        $8, %esp
        movl        $5, 4(%esp)
        movl        $1, (%esp)
        call        test
        movl        $0, %eax
        leave
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
        .cfi_endproc
.LFE1:
        .size        main, .-main
        .ident        "GCC: (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3"
        .section        .note.GNU-stack,"",@progbits




inline汇编:
        .file        "2.c"
        .text
        .globl        main
        .type        main, @function
main:
.LFB1:
        .cfi_startproc
        pushl        %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl        %esp, %ebp
        .cfi_def_cfa_register 5
        subl        $16, %esp
        movl        $1, -12(%ebp)
        movl        $5, -8(%ebp)
        movl        -8(%ebp), %eax
        movl        -12(%ebp), %edx
        addl        %edx, %eax
        movl        %eax, -4(%ebp)
        movl        $0, %eax
        leave
        .cfi_restore 5
        .cfi_def_cfa 4, 4
        ret
        .cfi_endproc
.LFE1:
        .size        main, .-main
        .ident        "GCC: (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3"
        .section        .note.GNU-stack,"",@progbits
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP