美文网首页
笔记 | 计算机系统基础:06-为什么不建议用递归?

笔记 | 计算机系统基础:06-为什么不建议用递归?

作者: KPlayer | 来源:发表于2020-01-11 11:03 被阅读0次
零. 课程要点:
  • If-else语句
  • switch-case语句
  • do~while/while/for循环语句
  • 循环与递归的比较

这一节主要介绍常见流程控制语句的机器级表示。有了前面的基础,这里的内容就比较简单。

一. If-else语句
if (cond_expr)
  then_statement
else
  else_statement

常见的用法有如下两种形式:

  c = cond_expr;
  if (!c)
    goto false_label;
  then_statement
  goto done
false_label:
  else_statement
done:
  c = cond_expr;
  if (c)
    goto true_label;
  else_statement
  goto done
true_label:
  then_statement
done:

举例有以下代码:

int get_cont( int *p1, int *p2 ) {
  if ( p1 > p2 )
    return *p2;
  else
    return *p1;
} 

其对应的汇编语句如下:

If-else
二. switch-case语句

在执行switch语句时,会先根据取值生成跳转表,存储着跳转标签和取值的对应关系,如下图所示:

switch-case

这里的实现有点绕,a的判断取值可能有10,12,14,15,17,和其它,可是跳转表生成了从10到17的对应标签,插了11,13,16。这是因为之后要使用jmp *.L8(, %eax, 4)来跳转,也就是转.L8+4*i处,所以一进来就把a减10,使得i可以从0开始计算。并且把defalut情况优先处理掉。然后根据不同的a值,跳转到不同的标签处执行。

所以这里有一个问题,如果a的取值范围过于离散,如1,988,19999,那么这个跳转表就要插入很多的值,显得累赘过大,因此switch比较适合变量取值集中在某一范围之内的情况。

三. do~while/while/for循环
do~while/while/for循环
四. 循环与递归的比较

递归是个看起来很高大上的东西,递归思想也令人觉得很美妙,能够用简洁的语句实现复杂的循环判断语句。但在具体实现过程中,也许并不是很好的选择,只是让你的代码看上去牛逼了一点。

我们来看一个实现前n个整数相加的函数:

int nn_sum ( int n)
{
  int i;
  int result=0;

  for (i=1; i<=n; i++)
    result+=i;

  return result;
}

上面用了循环的语句实现,因此只需要用比较指令和跳转指令实现,具体如下:

循环语句

这个过程中只用到ebp用来取入口参数,局部变量i和result分别分配在edx和eax中,因此其栈帧仅占用4字节空间,若考虑栈帧按16B对齐,也仅用16字节。

那么用递归方式实现呢?

int nn_sum ( int n) {
  int result;

  if (n<=0 )
    result=0;
  else
    result=n+nn_sum(n-1); 

  return result;
}

由于每一次递归都要调用一次函数,所以每次都要开辟一个栈帧,总共需要16n字节,空间的消耗很大。

递归语句

除此之外,每次递归调用都要执行16条指令,一共执行了n次过程调用,共16n条指令,比循环方式多不少。

由此看出,递归精简了代码,但是对空间和指令的消耗更大。为提高程序性能,能用非递归方式执行则最好用非递归方式。不过递归思想还是要认真掌握的,随着计算机性能的发展,也许这点开销不算什么,程序猿们可以追求自己心中的美学。

相关文章

网友评论

      本文标题:笔记 | 计算机系统基础:06-为什么不建议用递归?

      本文链接:https://www.haomeiwen.com/subject/plyvactx.html