引言
最近上班想到书中所说的每种循环的执行效率是不同的,而具体情况是怎么样我也记不清了,乘着有时间来研究研究,所以写下了这片博文。本文通过查看汇编代码比较各循环的效率以及i++,++i,i--,--i在循环中使用的效率问题,仅供抛砖引玉,测试平台操作系统为ubuntu,CPU为intel i5 4440,编译器为gcc-4.8.2。
测试代码1
此段代码我们主要测试在i--,--i,i++,++i的情况下,for循环、dowhile循环、while循环之间的执行效率情况。
- #include <stdio.h>
- /* 用于测试i--的while,for,dowhile循环情况 */
- void minus1 (void)
- {
- int i = 10;
- /* i-- while循环 */
- while (i--)
- ;
- i = 10;
- /* i-- dowhile循环 */
- do
- ;
- while (i--);
- /* i-- for循环 */
- for (i = 10; i != 0; i--)
- ;
- }
- /* 用于测试--i的while,for,dowhile循环情况 */
- void minus (void)
- {
- int i = 10;
- /* --i while循环 */
- while (--i)
- ;
- i = 10;
- /* --i dowhile循环 */
- do
- ;
- while (--i);
- /* --i for循环 */
- for (i = 10; i != 0; --i)
- ;
- }
- /* 用于测试i++的while,for,dowhile循环情况 */
- void plus1 (void)
- {
- int i = 0;
- /* i++ while循环 */
- while (i++ < 10)
- ;
- i = 0;
- /* i++ dowhile循环 */
- do
- ;
- while (i++ < 10);
- /* i++ for循环 */
- for (i = 0; i < 10; i++)
- ;
- }
- /* 用于测试++i的while,for,dowhile循环情况 */
- void plus (void)
- {
- int i = 0;
- /* ++i while循环 */
- while (++i < 10)
- ;
- i = 0;
- /* ++i dowhile循环 */
- do
- ;
- while (++i < 10);
- /* ++i for循环 */
- for (i = 0; i < 10; ++i)
- ;
- }
- int main (int argc, char * argv[])
- {
- return 0;
- }
好的,通过以上简单的代码,在linux下编译时加上{-g -Wall},再用{objdump -S 执行文件}命令即可查看运行文件的汇编代码,具体如下
- #include <stdio.h>
- void minus1 (void)
- {
- 4004ed: 55 push %rbp
- 4004ee: 48 89 e5 mov %rsp,%rbp
- int i = 10;
- 4004f1: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) # i = 10
- while (i--) # while (i--)
- 4004f8: 90 nop # 空指令
- 4004f9: 8b 45 fc mov -0x4(%rbp),%eax # eax = i 主循环
- 4004fc: 8d 50 ff lea -0x1(%rax),%edx # edx = rax - 1(rax的低32位为eax) 主循环
- 4004ff: 89 55 fc mov %edx,-0x4(%rbp) # i = edx 主循环
- 400502: 85 c0 test %eax,%eax # 等同于(i & i), 如果i不等于0,则结果也不为0 主循环
- 400504: 75 f3 jne 4004f9 <minus1+0xc> # 不等于0则跳转至4004f9 主循环
- ;
- i = 10;
- 400506: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) # i = 10
- do
- ;
- while (i--); # do ... while (i--);
- 40050d: 8b 45 fc mov -0x4(%rbp),%eax # eax = i 主循环
- 400510: 8d 50 ff lea -0x1(%rax),%edx # edx = rax - 1(rax的低32位为eax) 主循环
- 400513: 89 55 fc mov %edx,-0x4(%rbp) # i = edx 主循环
- 400516: 85 c0 test %eax,%eax # 等同于(i & i), 如果i不等于0,则结果也不为0 主循环
- 400518: 75 f3 jne 40050d <minus1+0x20> # 不等于0则跳转至40050d 主循环
- for (i = 10; i != 0; i--) # for (i = 10; i != 0; i--)
- 40051a: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) # i = 10
- 400521: eb 04 jmp 400527 <minus1+0x3a> # 跳转至400527
- 400523: 83 6d fc 01 subl $0x1,-0x4(%rbp) # i = i - 1 主循环
- 400527: 83 7d fc 00 cmpl $0x0,-0x4(%rbp) # i与0进行比较 主循环
- 40052b: 75 f6 jne 400523 <minus1+0x36> # 比较结果不等于0则跳转至400523 主循环
- ;
- }
- void minus (void)
- {
- 40052f: 55 push %rbp
- 400530: 48 89 e5 mov %rsp,%rbp
- int i = 10;
- 400533: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp)
- while (--i) # while (--i)
- 40053a: 83 6d fc 01 subl $0x1,-0x4(%rbp) # i = i - 1 主循环
- 40053e: 83 7d fc 00 cmpl $0x0,-0x4(%rbp) # i与0比较 主循环
- 400542: 75 f6 jne 40053a <minus+0xb> # 比较结果不等于0则跳转至40053a 主循环
- ;
- i = 10;
- 400544: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp)
- do
- ;
- while (--i); # do ... while (--i);
- 40054b: 83 6d fc 01 subl $0x1,-0x4(%rbp) # i = i - 1 主循环
- 40054f: 83 7d fc 00 cmpl $0x0,-0x4(%rbp) # i与0比较 主循环
- 400553: 75 f6 jne 40054b <minus+0x1c> # 比较结果不等于0则跳转至40054b 主循环
- for (i = 10; i != 0; --i) # for (i = 10; i != 0; --i)
- 400555: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) # i = 10
- 40055c: eb 04 jmp 400562 <minus+0x33> # 跳转至400562
- 40055e: 83 6d fc 01 subl $0x1,-0x4(%rbp) # i = i - 1 主循环
- 400562: 83 7d fc 00 cmpl $0x0,-0x4(%rbp) # i与0比较 主循环
- 400566: 75 f6 jne 40055e <minus+0x2f> # 比较结果不等于0则跳转至40055e 主循环
- ;
- }
- void plus1 (void)
- {
- 40056a: 55 push %rbp
- 40056b: 48 89 e5 mov %rsp,%rbp
- int i = 0;
- 40056e: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
- while (i++ < 10) # while (i++ < 10)
- 400575: 90 nop
- 400576: 8b 45 fc mov -0x4(%rbp),%eax # eax = i 主循环
- 400579: 8d 50 01 lea 0x1(%rax),%edx # edx = rax + 1(rax的低32位为eax) 主循环
- 40057c: 89 55 fc mov %edx,-0x4(%rbp) # i = edx 主循环
- 40057f: 83 f8 09 cmp $0x9,%eax # eax与9比较 主循环
- 400582: 7e f2 jle 400576 <plus1+0xc> # 比较结果不成立则跳转至400576 主循环
- ;
- i = 0;
- 400584: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
- do
- ;
- while (i++ < 10); # while (i++ < 10);
- 40058b: 8b 45 fc mov -0x4(%rbp),%eax # eax = i 主循环
- 40058e: 8d 50 01 lea 0x1(%rax),%edx # edx = rax + 1(rax的低32位为eax) 主循环
- 400591: 89 55 fc mov %edx,-0x4(%rbp) # i = edx 主循环
- 400594: 83 f8 09 cmp $0x9,%eax # eax与9比较 主循环
- 400597: 7e f2 jle 40058b <plus1+0x21> # 比较结果不成立则跳转至40058b 主循环
- for (i = 0; i < 10; i++) # for (i = 0; i < 10; i++)
- 400599: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) # i = 0
- 4005a0: eb 04 jmp 4005a6 <plus1+0x3c> # 跳转至4005a6
- 4005a2: 83 45 fc 01 addl $0x1,-0x4(%rbp) # i = i + 1 主循环
- 4005a6: 83 7d fc 09 cmpl $0x9,-0x4(%rbp) # i与9比较 主循环
- 4005aa: 7e f6 jle 4005a2 <plus1+0x38> # 比较结果不成立则跳转至4005a2 主循环
- ;
- }
- void plus (void)
- {
- 4005ae: 55 push %rbp
- 4005af: 48 89 e5 mov %rsp,%rbp
- int i = 0;
- 4005b2: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
- while (++i < 10) # while (++i < 10)
- 4005b9: 83 45 fc 01 addl $0x1,-0x4(%rbp) # i = i + 1 主循环
- 4005bd: 83 7d fc 09 cmpl $0x9,-0x4(%rbp) # i与9比较 主循环
- 4005c1: 7e f6 jle 4005b9 <plus+0xb> # 比较结果不成立则跳转至4005b9 主循环
- ;
- i = 0;
- 4005c3: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
- do
- ;
- while (++i < 10); # while (++i < 10);
- 4005ca: 83 45 fc 01 addl $0x1,-0x4(%rbp) # i = i + 1 主循环
- 4005ce: 83 7d fc 09 cmpl $0x9,-0x4(%rbp) # i与9比较 主循环
- 4005d2: 7e f6 jle 4005ca <plus+0x1c> # 比较结果不成立则跳转至4005b9 主循环
- for (i = 0; i < 10; ++i) # for (i = 0; i < 10; ++i)
- 4005d4: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) # i = 0
- 4005db: eb 04 jmp 4005e1 <plus+0x33> # 跳转至4005e1
- 4005dd: 83 45 fc 01 addl $0x1,-0x4(%rbp) # i = i + 1 主循环
- 4005e1: 83 7d fc 09 cmpl $0x9,-0x4(%rbp) # i与9比较 主循环
- 4005e5: 7e f6 jle 4005dd <plus+0x2f> # 比较结果不成立则跳转至4005dd 主循环
- ;
- }
根据上述汇编代码,将其制成表格
while主循环指令数 | do...while主循环指令数 | for主循环指令数 | |
i-- | 5 | 5 | 3 |
--i | 3 | 3 | 3 |
i++ | 5 | 5 | 3 |
++i | 3 | 3 | 3 |
小结
根据表格可清楚地看出,在while循环,do...while循环和for循环中,最优的循环效率为3条汇编指令,最不理想的情况为5条指令,对应的5条指令是在while循环和do...while循环中使用i--和i++控制循环的情况下产生的,效率较低,而其他情况下都为3条指令实现循环。在其中比较突出的是for循环,在for循环中无论使用i--,--i,i++还是++i控制循环都是最优的3条指令结构。而使用--i和++i控制循环结构的情况下,无论哪一种循环都是最优的主循环结构(3条指令)。