引言
大家都知道每種循環對應的效率是不同的,書中都說在循環中使用減法的效率是比加法的效率高的,具體情況是怎么樣,我們將詳細列出各循環的執行效率問題。本文通過查看匯編代碼比較各循環的效率以及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條匯編代碼。
