引言

  最近上班想到书中所说的每种循环的执行效率是不同的,而具体情况是怎么样我也记不清了,乘着有时间来研究研究,所以写下了这片博文。本文通过查看汇编代码比较各循环的效率以及i++,++i,i--,--i在循环中使用的效率问题,仅供抛砖引玉,测试平台操作系统为ubuntu,CPU为intel i5 4440,编译器为gcc-4.8.2。

测试代码1

  此段代码我们主要测试在i--,--i,i++,++i的情况下,for循环、dowhile循环、while循环之间的执行效率情况。

  1. #include <stdio.h>

  2. /* 用于测试i--的while,for,dowhile循环情况 */
  3. void minus1 (void)
  4. {
  5.     int i = 10;

  6.     /* i-- while循环 */
  7.     while (i--)
  8.         ;

  9.     i = 10;

  10.     /* i-- dowhile循环 */
  11.     do
  12.         ;
  13.     while (i--);

  14.     /* i-- for循环 */
  15.     for (i = 10; i != 0; i--)
  16.         ;
  17. }

  18. /* 用于测试--i的while,for,dowhile循环情况 */
  19. void minus (void)
  20. {
  21.     int i = 10;

  22.     /* --i while循环 */
  23.     while (--i)
  24.         ;

  25.     i = 10;

  26.     /* --i dowhile循环 */
  27.     do
  28.         ;
  29.     while (--i);

  30.     /* --i for循环 */
  31.     for (i = 10; i != 0; --i)
  32.         ;
  33. }

  34. /* 用于测试i++的while,for,dowhile循环情况 */
  35. void plus1 (void)
  36. {
  37.     int i = 0;

  38.     /* i++ while循环 */
  39.     while (i++ < 10)
  40.         ;

  41.     i = 0;

  42.     /* i++ dowhile循环 */
  43.     do
  44.         ;
  45.     while (i++ < 10);

  46.     /* i++ for循环 */
  47.     for (i = 0; i < 10; i++)
  48.         ;
  49. }

  50. /* 用于测试++i的while,for,dowhile循环情况 */
  51. void plus (void)
  52. {
  53.     int i = 0;

  54.     /* ++i while循环 */
  55.     while (++i < 10)
  56.         ;

  57.     i = 0;

  58.     /* ++i dowhile循环 */
  59.     do
  60.         ;
  61.     while (++i < 10);

  62.     /* ++i for循环 */
  63.     for (i = 0; i < 10; ++i)
  64.         ;
  65. }


  66. int main (int argc, char * argv[])
  67. {
  68.     return 0;
  69. }

    好的,通过以上简单的代码,在linux下编译时加上{-g -Wall},再用{objdump -S 执行文件}命令即可查看运行文件的汇编代码,具体如下

  1. #include <stdio.h>

  2. void minus1 (void)
  3. {
  4.   4004ed:    55     push %rbp
  5.   4004ee:    48 89 e5     mov %rsp,%rbp
  6.     int i = 10;
  7.   4004f1:    c7 45 fc 0a 00 00 00     movl $0xa,-0x4(%rbp)             # i = 10

  8.     while (i--)                                                        # while (i--)
  9.   4004f8:    90     nop                                                # 空指令
  10.   4004f9:    8b 45 fc     mov -0x4(%rbp),%eax                          # eax = i                                        主循环
  11.   4004fc:    8d 50 ff     lea -0x1(%rax),%edx                          # edx = rax - 1(rax的低32位为eax)                 主循环
  12.   4004ff:    89 55 fc     mov %edx,-0x4(%rbp)                          # i = edx                                        主循环
  13.   400502:    85 c0     test %eax,%eax                                  # 等同于(i & i), 如果i不等于0,则结果也不为0          主循环
  14.   400504:    75 f3     jne 4004f9 <minus1+0xc>                         # 不等于0则跳转至4004f9                            主循环
  15.         ;

  16.     i = 10;
  17.   400506:    c7 45 fc 0a 00 00 00     movl $0xa,-0x4(%rbp)             # i = 10

  18.     do
  19.         ;
  20.     while (i--);                                                       # do ... while (i--);
  21.   40050d:    8b 45 fc     mov -0x4(%rbp),%eax                          # eax = i                                        主循环
  22.   400510:    8d 50 ff     lea -0x1(%rax),%edx                          # edx = rax - 1(rax的低32位为eax)                 主循环
  23.   400513:    89 55 fc     mov %edx,-0x4(%rbp)                          # i = edx                                        主循环
  24.   400516:    85 c0     test %eax,%eax                                  # 等同于(i & i), 如果i不等于0,则结果也不为0          主循环
  25.   400518:    75 f3     jne 40050d <minus1+0x20>                        # 不等于0则跳转至40050d                            主循环

  26.     for (i = 10; i != 0; i--)                                          # for (i = 10; i != 0; i--)
  27.   40051a:    c7 45 fc 0a 00 00 00     movl $0xa,-0x4(%rbp)             # i = 10
  28.   400521:    eb 04     jmp 400527 <minus1+0x3a>                        # 跳转至400527
  29.   400523:    83 6d fc 01     subl $0x1,-0x4(%rbp)                      # i = i - 1                                      主循环
  30.   400527:    83 7d fc 00     cmpl $0x0,-0x4(%rbp)                      # i与0进行比较                                    主循环
  31.   40052b:    75 f6     jne 400523 <minus1+0x36>                        # 比较结果不等于0则跳转至400523                     主循环
  32.         ;
  33. }

  34. void minus (void)
  35. {
  36.   40052f:    55     push %rbp
  37.   400530:    48 89 e5     mov %rsp,%rbp
  38.     int i = 10;
  39.   400533:    c7 45 fc 0a 00 00 00     movl $0xa,-0x4(%rbp)

  40.     while (--i)                                                     # while (--i)
  41.   40053a:    83 6d fc 01     subl $0x1,-0x4(%rbp)                   # i = i - 1                                        主循环
  42.   40053e:    83 7d fc 00     cmpl $0x0,-0x4(%rbp)                   # i与0比较                                          主循环
  43.   400542:    75 f6     jne 40053a <minus+0xb>                       # 比较结果不等于0则跳转至40053a                       主循环
  44.         ;

  45.     i = 10;
  46.   400544:    c7 45 fc 0a 00 00 00     movl $0xa,-0x4(%rbp)

  47.     do
  48.         ;
  49.     while (--i);                                                     # do ... while (--i);
  50.   40054b:    83 6d fc 01     subl $0x1,-0x4(%rbp)                    # i = i - 1                                       主循环
  51.   40054f:    83 7d fc 00     cmpl $0x0,-0x4(%rbp)                    # i与0比较                                         主循环
  52.   400553:    75 f6     jne 40054b <minus+0x1c>                       # 比较结果不等于0则跳转至40054b                      主循环

  53.     for (i = 10; i != 0; --i)                                        # for (i = 10; i != 0; --i)
  54.   400555:    c7 45 fc 0a 00 00 00     movl $0xa,-0x4(%rbp)           # i = 10
  55.   40055c:    eb 04     jmp 400562 <minus+0x33>                       # 跳转至400562
  56.   40055e:    83 6d fc 01     subl $0x1,-0x4(%rbp)                    # i = i - 1                                       主循环
  57.   400562:    83 7d fc 00     cmpl $0x0,-0x4(%rbp)                    # i与0比较                                         主循环
  58.   400566:    75 f6     jne 40055e <minus+0x2f>                       # 比较结果不等于0则跳转至40055e                      主循环
  59.         ;
  60. }

  61. void plus1 (void)
  62. {
  63.   40056a:    55     push %rbp
  64.   40056b:    48 89 e5     mov %rsp,%rbp
  65.     int i = 0;
  66.   40056e:    c7 45 fc 00 00 00 00     movl $0x0,-0x4(%rbp)

  67.     while (i++ < 10)                                                 # while (i++ < 10)     
  68.   400575:    90     nop
  69.   400576:    8b 45 fc     mov -0x4(%rbp),%eax                        # eax = i                                         主循环
  70.   400579:    8d 50 01     lea 0x1(%rax),%edx                         # edx = rax + 1(rax的低32位为eax)                  主循环
  71.   40057c:    89 55 fc     mov %edx,-0x4(%rbp)                        # i = edx                                         主循环
  72.   40057f:    83 f8 09     cmp $0x9,%eax                              # eax与9比较                                       主循环
  73.   400582:    7e f2     jle 400576 <plus1+0xc>                        # 比较结果不成立则跳转至400576                       主循环
  74.         ;

  75.     i = 0;
  76.   400584:    c7 45 fc 00 00 00 00     movl $0x0,-0x4(%rbp)

  77.     do
  78.         ;
  79.     while (i++ < 10);                                                # while (i++ < 10);
  80.   40058b:    8b 45 fc     mov -0x4(%rbp),%eax                        # eax = i                                         主循环
  81.   40058e:    8d 50 01     lea 0x1(%rax),%edx                         # edx = rax + 1(rax的低32位为eax)                  主循环
  82.   400591:    89 55 fc     mov %edx,-0x4(%rbp)                        # i = edx                                         主循环
  83.   400594:    83 f8 09     cmp $0x9,%eax                              # eax与9比较                                       主循环
  84.   400597:    7e f2     jle 40058b <plus1+0x21>                       # 比较结果不成立则跳转至40058b                       主循环

  85.     for (i = 0; i < 10; i++)                                         # for (i = 0; i < 10; i++)
  86.   400599:    c7 45 fc 00 00 00 00     movl $0x0,-0x4(%rbp)           # i = 0                                         
  87.   4005a0:    eb 04     jmp 4005a6 <plus1+0x3c>                       # 跳转至4005a6                                     
  88.   4005a2:    83 45 fc 01     addl $0x1,-0x4(%rbp)                    # i = i + 1                                       主循环
  89.   4005a6:    83 7d fc 09     cmpl $0x9,-0x4(%rbp)                    # i与9比较                                         主循环
  90.   4005aa:    7e f6     jle 4005a2 <plus1+0x38>                       # 比较结果不成立则跳转至4005a2                       主循环
  91.         ;
  92. }

  93. void plus (void)
  94. {
  95.   4005ae:    55     push %rbp
  96.   4005af:    48 89 e5     mov %rsp,%rbp
  97.     int i = 0;
  98.   4005b2:    c7 45 fc 00 00 00 00     movl $0x0,-0x4(%rbp)

  99.     while (++i < 10)                                                 # while (++i < 10)
  100.   4005b9:    83 45 fc 01     addl $0x1,-0x4(%rbp)                    # i = i + 1                                      主循环
  101.   4005bd:    83 7d fc 09     cmpl $0x9,-0x4(%rbp)                    # i与9比较                                        主循环
  102.   4005c1:    7e f6     jle 4005b9 <plus+0xb>                         # 比较结果不成立则跳转至4005b9                       主循环
  103.         ;

  104.     i = 0;
  105.   4005c3:    c7 45 fc 00 00 00 00     movl $0x0,-0x4(%rbp)

  106.     do
  107.         ;
  108.     while (++i < 10);                                                # while (++i < 10);
  109.   4005ca:    83 45 fc 01     addl $0x1,-0x4(%rbp)                    # i = i + 1                                      主循环
  110.   4005ce:    83 7d fc 09     cmpl $0x9,-0x4(%rbp)                    # i与9比较                                        主循环
  111.   4005d2:    7e f6     jle 4005ca <plus+0x1c>                        # 比较结果不成立则跳转至4005b9                      主循环

  112.     for (i = 0; i < 10; ++i)                                         # for (i = 0; i < 10; ++i)
  113.   4005d4:    c7 45 fc 00 00 00 00     movl $0x0,-0x4(%rbp)           # i = 0
  114.   4005db:    eb 04     jmp 4005e1 <plus+0x33>                        # 跳转至4005e1
  115.   4005dd:    83 45 fc 01     addl $0x1,-0x4(%rbp)                    # i = i + 1                                       主循环
  116.   4005e1:    83 7d fc 09     cmpl $0x9,-0x4(%rbp)                    # i与9比较                                         主循环
  117.   4005e5:    7e f6     jle 4005dd <plus+0x2f>                        # 比较结果不成立则跳转至4005dd                       主循环
  118.         ;
  119. }

根据上述汇编代码,将其制成表格

while主循环指令数do...while循环指令数for循环指令数
i--553
--i333
i++553
++i333

小结

    根据表格可清楚地看出,在while循环,do...while循环和for循环中,最优的循环效率为3条汇编指令,最不理想的情况为5条指令,对应的5条指令是在while循环和do...while循环中使用i--和i++控制循环的情况下产生的,效率较低,而其他情况下都为3条指令实现循环。在其中比较突出的是for循环,在for循环中无论使用i--,--i,i++还是++i控制循环都是最优的3条指令结构。而使用--i和++i控制循环结构的情况下,无论哪一种循环都是最优的主循环结构(3条指令)。



10-08 06:14