之前听前辈说过,使用 if else 时,大概率执行的执行体的位置是有所考究的。
今天编写对效率敏感的代码时又想起了这个,当时没有实际去验证这一说法,今天就趁机进行了一下验证。
示例代码如下:
#include "stdio.h"
int main(int argc, char **argv)
{
int i;
int a = 1;
int b = 0;
if(a > b){
i = 1;
}else{
i = 0;
}
printf("%d",i);
return 0;
}
使用 VC 编译并提取编译后的部分汇编代码如下:
9: if(a > b)
0040D7C6 mov eax,dword ptr [ebp-8]
0040D7C9 cmp eax,dword ptr [ebp-0Ch]
0040D7CC jle main+37h (0040d7d7)
10: {
11: i = 1;
0040D7CE mov dword ptr [ebp-4],1
12: }else{
0040D7D5 jmp main+3Eh (0040d7de) //进入 if,会多执行 jmp 指令
13: i = 0;
0040D7D7 mov dword ptr [ebp-4],0
14: }
15:
16: printf("%d",i);
0040D7DE mov ecx,dword ptr [ebp-4]
0040D7E1 push ecx
0040D7E2 push offset string "%d" (0042201c)
0040D7E7 call printf (00401110)
0040D7EC add esp,8
17: return 0;
0040D7EF xor eax,eax
使用 gcc -S 编译源文件并提取汇编文件的部分代码如下:
subl $32, %esp
movl $1, 24(%esp)
movl $0, 28(%esp)
movl 24(%esp), %eax
cmpl 28(%esp), %eax
jle .L2
movl $1, 20(%esp)
jmp .L3 //进入 if,会多执行 jmp 指令
.L2:
movl $0, 20(%esp)
.L3:
movl $.LC0, %eax
movl 20(%esp), %edx
movl %edx, 4(%esp)
movl %eax, (%esp)
call printf
以上都是在没有经过编译器优化的情况下进行编译的,如果使用优化选项,编译的汇编代码会直接使用判断的结果来执行后续代码的。
总结:
通过以上验证过程可以得知,在频繁大量的使用 if else 的时候,按照如下方式来进行处理,会相应提高运行速度:
if(条件)
{
//放置执行次数少的执行体
}else{
//放置执行次数多的执行体
}
即 else 中放置条件满足次数多的执行体,这样可以减少跳转指令的调用次数;
一次判断,影响可以忽略不计,但多次重复调用,累积的结果还是会有一定影响,特别是在一些性能不强的硬件平台上使用的时候,应该尽量在软件上进行优化,提高运行效率。
在性能强大的硬件平台上,这点影响几乎可以忽略不计,因为 cpu 内部会有大量的结构来优化代码的执行效率,比如流水线结构等等····本人能力有限,在这里只能浅显的表述一下。
实用场景如下,函数被外部重复调用的前提下:
void vFunc(void)
{
static int i = 1000;
if(0 == i){
//执行其他需要的操作
}else{
i--;
}
}
以上执行就比下面的执行效率高一些
void vFunc(void)
{
static int i = 1000;
if(i>0){
i--; //此处每次都会比上面的执行多一条跳转指令
}else{
//执行其他需要的操作
}
}