复制两个版本,使用gcc -S 编译每个版本以获得机器语言输出,使用sdiff 并排比较。
使用 gcc 版本 4.1.2 20070115 (SUSE Linux) 的结果:
没有优化:
main: main:
.LFB2: .LFB2:
pushq %rbp pushq %rbp
.LCFI0: .LCFI0:
movq %rsp, %rbp movq %rsp, %rbp
.LCFI1: .LCFI1:
subq $16, %rsp subq $16, %rsp
.LCFI2: .LCFI2:
movl $0, %eax movl $0, %eax
call get_a_value call get_a_value
movl %eax, -8(%rbp) | movl %eax, %edi
movl -8(%rbp), %edi <
movl $0, %eax movl $0, %eax
call calculate_something call calculate_something
movl %eax, -4(%rbp) movl %eax, -4(%rbp)
movl -4(%rbp), %eax movl -4(%rbp), %eax
leave leave
ret ret
基本上,一个额外的移动指令。两者都分配相同数量的堆栈空间(subq $16, %rsp 为堆栈保留 16 个字节),因此在内存方面没有区别。
一级优化(-O1):
main: main:
.LFB2: .LFB2:
subq $8, %rsp subq $8, %rsp
.LCFI0: .LCFI0:
movl $0, %eax movl $0, %eax
call get_a_value call get_a_value
movl %eax, %edi movl %eax, %edi
movl $0, %eax movl $0, %eax
call calculate_something call calculate_something
addq $8, %rsp addq $8, %rsp
ret ret
没有区别。
使用 gcc 版本 2.96 20000731(Red Hat Linux 7.2 2.96-112.7.2)的结果:
没有优化:
main: main:
pushl %ebp pushl %ebp
movl %esp, %ebp movl %esp, %ebp
subl $8, %esp subl $8, %esp
> subl $12, %esp
> subl $4, %esp
call get_a_value call get_a_value
> addl $4, %esp
movl %eax, %eax movl %eax, %eax
movl %eax, -4(%ebp) | pushl %eax
subl $12, %esp <
pushl -4(%ebp) <
call calculate_something call calculate_something
addl $16, %esp addl $16, %esp
movl %eax, %eax movl %eax, %eax
movl %eax, -8(%ebp) | movl %eax, -4(%ebp)
movl -8(%ebp), %eax | movl -4(%ebp), %eax
movl %eax, %eax movl %eax, %eax
leave leave
ret ret
指令数量大致相同,排序略有不同。
一级优化(-O1):
main: main:
pushl %ebp pushl %ebp
movl %esp, %ebp movl %esp, %ebp
subl $8, %esp | subl $24, %esp
call get_a_value call get_a_value
subl $12, %esp | movl %eax, (%esp)
pushl %eax <
call calculate_something call calculate_something
leave leave
ret ret
看起来第二个版本保留了更多的堆栈空间。
因此,对于使用这些特定编译器的这个特定示例,两个版本之间没有太大区别。在这种情况下,我倾向于使用第一个版本,原因如下:
- 在调试器中更容易跟踪;您可以检查从
get_a_value 返回的值,然后再将其传递给calculate_something;
- 它为您提供了一个进行完整性检查的地方,以防
calculate_something 对于某些输入的行为不正常;
- 眼睛更容易一些。
请记住,简洁并不一定意味着快速或高效,在一种特定的编译器/硬件组合下快速/高效可能在不同的编译器/硬件组合下被无可救药地破坏。一些编译器实际上更容易优化以清晰方式编写的代码。
您的代码应该是:
- 正确 - 如果不满足要求,它的速度或使用的内存量如何无关紧要;
- 安全 - 如果它是恶意软件载体或有将敏感数据暴露给未经授权方的风险(是的,我说的是 Heart-流血);
- 稳健 - 如果因为有人在另一个房间打喷嚏而转储核心,它 并不重要 使用多少内存;
- 可维护 - 如果由于需求发生变化(他们确实如此)而不得不报废和重写它,那么它的速度有多快或使用的内存有多少并不重要;
- 高效 - 现在您可以开始担心性能和效率了。