zoukankan      html  css  js  c++  java
  • C语言中自加与自减效率的思考

    原帖地址:http://out.bitunion.org/thread-10461486-1-2.html

    在正常的C语言中,使用

     cpp 代码 [复制到剪贴板]
    1.  for (val = 0val < numval++)
    2.  for (val = numval > 0val--)
    从表面上看是一样的,通常我们的目的是使循环进行num次。然而在经典的C语言效率的讨论中,往往会有人说“第一种效率较第二种而言较低”。针对这一问题,昨天试图在C99手册上搜索相关说明,但是没有找到。因此我考虑这种效率的差异是由机器执行过程中产生的。至此,我决定通过反汇编的方式分析其中的差异。

    下面我们进行测试。
    首先编写一段测试代码,内容较为随意,只要应用到for循环就好了。我使用的是累加...

    正常编译,查看结果等就不罗嗦了。下面贴出自加与自减两段代码的汇编部分:

      代码: [复制到剪贴板]  
    1.     00000000 <test_addl>:
    2.        0:    55                       push   %ebp
    3.        1:    89 e5                    mov    %esp,%ebp
    4.        3:    83 ec 10                 sub    $0x10,%esp
    5.        6:    c7 45 fc 00 00 00 00     movl   $0x0,-0x4(%ebp)
    6.        d:    c7 45 f8 00 00 00 00     movl   $0x0,-0x8(%ebp)
    7.       14:    c7 45 fc 00 00 00 00     movl   $0x0,-0x4(%ebp)
    8.       1b:    eb 0a                    jmp    27 <test_addl+0x27>
    9.       1d:    8b 45 fc                 mov    -0x4(%ebp),%eax
    10.       20:    01 45 f8                 add    %eax,-0x8(%ebp)
    11.       23:    83 45 fc 01              addl   $0x1,-0x4(%ebp)
    12.       27:    8b 45 fc                 mov    -0x4(%ebp),%eax
    13.       2a:    3b 45 08                 cmp    0x8(%ebp),%eax
    14.       2d:    7c ee                    jl     1d <test_addl+0x1d>
    15.       2f:    8b 45 f8                 mov    -0x8(%ebp),%eax
    16.       32:    c9                       leave  
    17.       33:    c3                       ret   
    18.     00000034 <test_subl>:
    19.       34:    55                       push   %ebp
    20.       35:    89 e5                    mov    %esp,%ebp
    21.       37:    83 ec 10                 sub    $0x10,%esp
    22.       3a:    c7 45 fc 00 00 00 00     movl   $0x0,-0x4(%ebp)
    23.       41:    c7 45 f8 00 00 00 00     movl   $0x0,-0x8(%ebp)
    24.       48:    8b 45 08                 mov    0x8(%ebp),%eax
    25.       4b:    89 45 fc                 mov    %eax,-0x4(%ebp)
    26.       4e:    eb 0a                    jmp    5a <test_subl+0x26>
    27.       50:    8b 45 fc                 mov    -0x4(%ebp),%eax
    28.       53:    01 45 f8                 add    %eax,-0x8(%ebp)
    29.       56:    83 6d fc 01              subl   $0x1,-0x4(%ebp)
    30.       5a:    83 7d fc 00              cmpl   $0x0,-0x4(%ebp)
    31.       5e:    7f f0                    jg     50 <test_subl+0x1c>
    32.       60:    8b 45 f8                 mov    -0x8(%ebp),%eax
    33.       63:    c9                       leave  
    34.       64:    c3                       ret   



      代码: [复制到剪贴板]  
    1.     00000000 <test_addl>:
    2.        0:    55                       push   %ebp
    3.        1:    31 c0                    xor    %eax,%eax
    4.        3:    89 e5                    mov    %esp,%ebp
    5.        5:    31 d2                    xor    %edx,%edx
    6.        7:    8b 4d 08                 mov    0x8(%ebp),%ecx
    7.        a:    85 c9                    test   %ecx,%ecx
    8.        c:    7e 0b                    jle    19 <test_addl+0x19>
    9.        e:    66 90                    xchg   %ax,%ax
    10.       10:    01 d0                    add    %edx,%eax
    11.       12:    83 c2 01                 add    $0x1,%edx
    12.       15:    39 ca                    cmp    %ecx,%edx
    13.       17:    75 f7                    jne    10 <test_addl+0x10>
    14.       19:    5d                       pop    %ebp
    15.       1a:    c3                       ret   
    16.       1b:    90                       nop
    17.       1c:    8d 74 26 00              lea    0x0(%esi,%eiz,1),%esi
    18.     00000020 <test_subl>:
    19.       20:    55                       push   %ebp
    20.       21:    31 c0                    xor    %eax,%eax
    21.       23:    89 e5                    mov    %esp,%ebp
    22.       25:    8b 55 08                 mov    0x8(%ebp),%edx
    23.       28:    85 d2                    test   %edx,%edx
    24.       2a:    7e 0b                    jle    37 <test_subl+0x17>
    25.       2c:    8d 74 26 00              lea    0x0(%esi,%eiz,1),%esi
    26.       30:    01 d0                    add    %edx,%eax
    27.       32:    83 ea 01                 sub    $0x1,%edx
    28.       35:    75 f9                    jne    30 <test_subl+0x10>
    29.       37:    5d                       pop    %ebp
    30.       38:    c3                       ret   
    31.       39:    8d b4 26 00 00 00 00     lea    0x0(%esi,%eiz,1),%esi

    上述两部分编译不一样...第二段使用-O2优化了一下...

    对比一下,就能看出问题了...自减是不需要判断的,并且节约代码...
    产生原因很纠结...

    查阅《ARM体系结构与编程》,书中间接指出了原因:
    在执行sub时,程序状态寄存器可以直接通过Z标志位对结果判断是否为0(C标志位判断溢出),从而判断循环是否结束。而在执行add时,程序状态寄存器仅仅可以通过C标志位判断是否有溢出。所以导致自加过程中需要指令mov
  • 相关阅读:
    Layui 两个table 人员选择 多选
    iphone7 忘记密码 重装系统
    使用hql-统计连续登陆的三天及以上的用户
    azkaban群起/群停脚本
    Hive读取索引文件问题:select * 和select count(*)读取出来的行数不一致
    scala/java等其他语言从CSV文件中读取数据,使用逗号','分割可能会出现的问题
    hadoop3.1.3版本的secondaryNamenode的web界面不能显示的问题?
    启动kafka消费报错:WARN [Consumer clientId…] 1 partitions have leader brokers without a matching listener,…
    centos6和centos7的防火墙命令,以及它们的区别是是什么?
    kafka项目经验之如何进行Kafka压力测试、如何计算Kafka分区数、如何确定Kaftka集群机器数量
  • 原文地址:https://www.cnblogs.com/church/p/2603959.html
Copyright © 2011-2022 走看看