看到有朋友提到《深入理解计算机系统结构》这本书了,我这边贴上一些学习资源供大家参考,和本题相关的内容在书中第三章,可以直接精准查阅。因为我只是按照前人的方法来自己去手动验证了一下生成汇编代码的结果,并没有谈及理论内容,所以我想提问者可能需要更系统和理论的支撑。
然后的话,我在回答最后把书中涉及到for和while的部分截图放上来了,不想下载的也可以直接看我的回答最后的附录。
1.英文版原书和配套资料(Computer Systems: A Programmer's Perspective(3rd))
2.中文版《深入理解计算机系统结构》(提取码wrzg)
关于本问题,我在Linux上做了一个测试程序:
首先写了下面的C代码文件test.c:
#include <stdio.h> int main() { int i; int j; int sum = 0; for (i = 0; i < 10; ++i) { sum += i; } j = 0; while (j < 10) { sum += j; ++j; } return 0; }
接着编译一下:
gcc -o test test.c
然后使用objdump -d作为反汇编器得到汇编代码
objdump -d test> test.txt
打开test.txt看一下
0000000000400474 <main>: 400474: 55 push %rbp 400475: 48 89 e5 mov %rsp,%rbp 400478: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) 40047f: c7 45 f4 00 00 00 00 movl $0x0,-0xc(%rbp) 400486: eb 0a jmp 400492 <main+0x1e> 400488: 8b 45 f4 mov -0xc(%rbp),%eax 40048b: 01 45 fc add %eax,-0x4(%rbp) 40048e: 83 45 f4 01 addl $0x1,-0xc(%rbp) 400492: 83 7d f4 09 cmpl $0x9,-0xc(%rbp) 400496: 7e f0 jle 400488 <main+0x14> 400498: c7 45 f8 00 00 00 00 movl $0x0,-0x8(%rbp) 40049f: eb 0a jmp 4004ab <main+0x37> 4004a1: 8b 45 f8 mov -0x8(%rbp),%eax 4004a4: 01 45 fc add %eax,-0x4(%rbp) 4004a7: 83 45 f8 01 addl $0x1,-0x8(%rbp) 4004ab: 83 7d f8 09 cmpl $0x9,-0x8(%rbp) 4004af: 7e f0 jle 4004a1 <main+0x2d> 4004b1: b8 00 00 00 00 mov $0x0,%eax 4004b6: c9 leaveq 4004b7: c3 retq 4004b8: 90 nop 4004b9: 90 nop 4004ba: 90 nop 4004bb: 90 nop 4004bc: 90 nop 4004bd: 90 nop 4004be: 90 nop 4004bf: 90 nop
可以看到
for循环的汇编代码如下:
... 40047f: c7 45 f4 00 00 00 00 movl $0x0,-0xc(%rbp) 400486: eb 0a jmp 400492 <main+0x1e> 400488: 8b 45 f4 mov -0xc(%rbp),%eax 40048b: 01 45 fc add %eax,-0x4(%rbp) 40048e: 83 45 f4 01 addl $0x1,-0xc(%rbp) 400492: 83 7d f4 09 cmpl $0x9,-0xc(%rbp) 400496: 7e f0 jle 400488 <main+0x14> ...
while循环的汇编代码如下:
... 400498: c7 45 f8 00 00 00 00 movl $0x0,-0x8(%rbp) 40049f: eb 0a jmp 4004ab <main+0x37> 4004a1: 8b 45 f8 mov -0x8(%rbp),%eax 4004a4: 01 45 fc add %eax,-0x4(%rbp) 4004a7: 83 45 f8 01 addl $0x1,-0x8(%rbp) 4004ab: 83 7d f8 09 cmpl $0x9,-0x8(%rbp) 4004af: 7e f0 jle 4004a1 <main+0x2d> ...
如你所见,这两个循环在程序集代码中遵循相同的结构,且操作数也都是相同的。
因此,对于在Linux上用GCC编译的C语言基本计数循环的默认优化来讲,while循环和for循环具有相同的性能。
当然,以上测试代码是比较简单的,在某些特殊情况下(例如动态条件等)可能某种循环结构的性能更好,或者因为编译器优化的方式不同而导致了不同的性能,这个还是需要具体问题来具体分析的。
按照书中的理论来说,GCC为for循环产生的优化可能是while循环优化的其中一种,这要取决于优化等级,我的理解是,这可能导致某些时候while和for循环的汇编码不相同,因为两者可能恰好采取不同的优化方式。
附《深入理解计算机系统》相关摘录:
以上,谢谢。