引言
大家都知道每种循环对应的效率是不同的,书中都说在循环中使用减法的效率是比加法的效率高的,具体情况是怎么样,我们将详细列出各循环的执行效率问题。本文通过查看汇编代码比较各循环的效率以及i++,++i,i–,–i在循环中使用的效率问题,仅供抛砖引玉,测试平台为intel i5 4440,编译器为gcc-4.8.2
测试代码1
此段代码我们主要测试在i–,–i,i++,++i的情况下,for循环、dowhile循环、while循环之间的执行效率情况
1 #include <stdio.h> 2 3 /* 用于测试i--的while,for,dowhile循环情况 */ 4 void minus1 (void) 5 { 6 int i = 10; 7 8 /* i-- while循环 */ 9 while (i--) 10 ; 11 12 i = 10; 13 14 /* i-- dowhile循环 */ 15 do 16 ; 17 while (i--); 18 19 /* i-- for循环 */ 20 for (i = 10; i != 0; i--) 21 ; 22 } 23 24 /* 用于测试--i的while,for,dowhile循环情况 */ 25 void minus (void) 26 { 27 int i = 10; 28 29 /* --i while循环 */ 30 while (--i) 31 ; 32 33 i = 10; 34 35 /* --i dowhile循环 */ 36 do 37 ; 38 while (--i); 39 40 /* --i for循环 */ 41 for (i = 10; i != 0; --i) 42 ; 43 } 44 45 /* 用于测试i++的while,for,dowhile循环情况 */ 46 void plus1 (void) 47 { 48 int i = 0; 49 50 /* i++ while循环 */ 51 while (i++ < 10) 52 ; 53 54 i = 0; 55 56 /* i++ dowhile循环 */ 57 do 58 ; 59 while (i++ < 10); 60 61 /* i++ for循环 */ 62 for (i = 0; i < 10; i++) 63 ; 64 } 65 66 /* 用于测试++i的while,for,dowhile循环情况 */ 67 void plus (void) 68 { 69 int i = 0; 70 71 /* ++i while循环 */ 72 while (++i < 10) 73 ; 74 75 i = 0; 76 77 /* ++i dowhile循环 */ 78 do 79 ; 80 while (++i < 10); 81 82 /* ++i for循环 */ 83 for (i = 0; i < 10; ++i) 84 ; 85 } 86 87 88 int main (int argc, char * argv[]) 89 { 90 return 0; 91 }
测试代码1所生成的汇编代码如下:
1 #include <stdio.h> 2 3 void minus1 (void) 4 { 5 4004ed: 55 push %rbp 6 4004ee: 48 89 e5 mov %rsp,%rbp 7 int i = 10; 8 4004f1: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) # i = 10 9 10 while (i--) # while (i--) 11 4004f8: 90 nop # 空指令 12 4004f9: 8b 45 fc mov -0x4(%rbp),%eax # eax = i 主循环 13 4004fc: 8d 50 ff lea -0x1(%rax),%edx # edx = rax - 1(rax的低32位为eax) 主循环 14 4004ff: 89 55 fc mov %edx,-0x4(%rbp) # i = edx 主循环 15 400502: 85 c0 test %eax,%eax # 等同于(i & i), 如果i不等于0,则结果也不为0 主循环 16 400504: 75 f3 jne 4004f9 <minus1+0xc> # 不等于0则跳转至4004f9 主循环 17 ; 18 19 i = 10; 20 400506: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) # i = 10 21 22 do 23 ; 24 while (i--); # do ... while (i--); 25 40050d: 8b 45 fc mov -0x4(%rbp),%eax # eax = i 主循环 26 400510: 8d 50 ff lea -0x1(%rax),%edx # edx = rax - 1(rax的低32位为eax) 主循环 27 400513: 89 55 fc mov %edx,-0x4(%rbp) # i = edx 主循环 28 400516: 85 c0 test %eax,%eax # 等同于(i & i), 如果i不等于0,则结果也不为0 主循环 29 400518: 75 f3 jne 40050d <minus1+0x20> # 不等于0则跳转至40050d 主循环 30 31 for (i = 10; i != 0; i--) # for (i = 10; i != 0; i--) 32 40051a: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) # i = 10 33 400521: eb 04 jmp 400527 <minus1+0x3a> # 跳转至400527 34 400523: 83 6d fc 01 subl $0x1,-0x4(%rbp) # i = i - 1 主循环 35 400527: 83 7d fc 00 cmpl $0x0,-0x4(%rbp) # i与0进行比较 主循环 36 40052b: 75 f6 jne 400523 <minus1+0x36> # 比较结果不等于0则跳转至400523 主循环 37 ; 38 } 39 40 void minus (void) 41 { 42 40052f: 55 push %rbp 43 400530: 48 89 e5 mov %rsp,%rbp 44 int i = 10; 45 400533: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) 46 47 while (--i) # while (--i) 48 40053a: 83 6d fc 01 subl $0x1,-0x4(%rbp) # i = i - 1 主循环 49 40053e: 83 7d fc 00 cmpl $0x0,-0x4(%rbp) # i与0比较 主循环 50 400542: 75 f6 jne 40053a <minus+0xb> # 比较结果不等于0则跳转至40053a 主循环 51 ; 52 53 i = 10; 54 400544: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) 55 56 do 57 ; 58 while (--i); # do ... while (--i); 59 40054b: 83 6d fc 01 subl $0x1,-0x4(%rbp) # i = i - 1 主循环 60 40054f: 83 7d fc 00 cmpl $0x0,-0x4(%rbp) # i与0比较 主循环 61 400553: 75 f6 jne 40054b <minus+0x1c> # 比较结果不等于0则跳转至40054b 主循环 62 63 for (i = 10; i != 0; --i) # for (i = 10; i != 0; --i) 64 400555: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) # i = 10 65 40055c: eb 04 jmp 400562 <minus+0x33> # 跳转至400562 66 40055e: 83 6d fc 01 subl $0x1,-0x4(%rbp) # i = i - 1 主循环 67 400562: 83 7d fc 00 cmpl $0x0,-0x4(%rbp) # i与0比较 主循环 68 400566: 75 f6 jne 40055e <minus+0x2f> # 比较结果不等于0则跳转至40055e 主循环 69 ; 70 } 71 72 void plus1 (void) 73 { 74 40056a: 55 push %rbp 75 40056b: 48 89 e5 mov %rsp,%rbp 76 int i = 0; 77 40056e: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) 78 79 while (i++ < 10) # while (i++ < 10) 80 400575: 90 nop 81 400576: 8b 45 fc mov -0x4(%rbp),%eax # eax = i 主循环 82 400579: 8d 50 01 lea 0x1(%rax),%edx # edx = rax + 1(rax的低32位为eax) 主循环 83 40057c: 89 55 fc mov %edx,-0x4(%rbp) # i = edx 主循环 84 40057f: 83 f8 09 cmp $0x9,%eax # eax与9比较 主循环 85 400582: 7e f2 jle 400576 <plus1+0xc> # 比较结果不成立则跳转至400576 主循环 86 ; 87 88 i = 0; 89 400584: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) 90 91 do 92 ; 93 while (i++ < 10); # while (i++ < 10); 94 40058b: 8b 45 fc mov -0x4(%rbp),%eax # eax = i 主循环 95 40058e: 8d 50 01 lea 0x1(%rax),%edx # edx = rax + 1(rax的低32位为eax) 主循环 96 400591: 89 55 fc mov %edx,-0x4(%rbp) # i = edx 主循环 97 400594: 83 f8 09 cmp $0x9,%eax # eax与9比较 主循环 98 400597: 7e f2 jle 40058b <plus1+0x21> # 比较结果不成立则跳转至40058b 主循环 99 100 for (i = 0; i < 10; i++) # for (i = 0; i < 10; i++) 101 400599: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) # i = 0 102 4005a0: eb 04 jmp 4005a6 <plus1+0x3c> # 跳转至4005a6 103 4005a2: 83 45 fc 01 addl $0x1,-0x4(%rbp) # i = i + 1 主循环 104 4005a6: 83 7d fc 09 cmpl $0x9,-0x4(%rbp) # i与9比较 主循环 105 4005aa: 7e f6 jle 4005a2 <plus1+0x38> # 比较结果不成立则跳转至4005a2 主循环 106 ; 107 } 108 109 void plus (void) 110 { 111 4005ae: 55 push %rbp 112 4005af: 48 89 e5 mov %rsp,%rbp 113 int i = 0; 114 4005b2: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) 115 116 while (++i < 10) # while (++i < 10) 117 4005b9: 83 45 fc 01 addl $0x1,-0x4(%rbp) # i = i + 1 主循环 118 4005bd: 83 7d fc 09 cmpl $0x9,-0x4(%rbp) # i与9比较 主循环 119 4005c1: 7e f6 jle 4005b9 <plus+0xb> # 比较结果不成立则跳转至4005b9 主循环 120 ; 121 122 i = 0; 123 4005c3: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) 124 125 do 126 ; 127 while (++i < 10); # while (++i < 10); 128 4005ca: 83 45 fc 01 addl $0x1,-0x4(%rbp) # i = i + 1 主循环 129 4005ce: 83 7d fc 09 cmpl $0x9,-0x4(%rbp) # i与9比较 主循环 130 4005d2: 7e f6 jle 4005ca <plus+0x1c> # 比较结果不成立则跳转至4005b9 主循环 131 132 for (i = 0; i < 10; ++i) # for (i = 0; i < 10; ++i) 133 4005d4: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) # i = 0 134 4005db: eb 04 jmp 4005e1 <plus+0x33> # 跳转至4005e1 135 4005dd: 83 45 fc 01 addl $0x1,-0x4(%rbp) # i = i + 1 主循环 136 4005e1: 83 7d fc 09 cmpl $0x9,-0x4(%rbp) # i与9比较 主循环 137 4005e5: 7e f6 jle 4005dd <plus+0x2f> # 比较结果不成立则跳转至4005dd 主循环 138 ; 139 }
可以从汇编代码得出如下表格
while主循环语句数 |
do…while主循环语句数 |
for主循环语句数 | |
i– | 5 | 5 | 3 |
–i | 3 | 3 | 3 |
i++ | 5 | 5 | 3 |
++i | 3 | 3 | 3 |
小结
可以从表中得出结论:循环效率最高也需要执行3条汇编语句,而最慢需要5条汇编语句,使用i–和i++进行循环控制时,不同的循环结构所对应的汇编代码量不同,最少的为for循环,只需要3条汇编指令,最多的为while循环,需要5条汇编指令,而当使用–i和++i进行循环控制时,无论哪一种循环结构执行效率都一样是最优的,都只需要3条代码,而无论使用i–,–i,i++,++i中哪一种,for循环的效率应该是最高的,都只用了3条汇编代码。