一步一步写算法(之函数堆栈显示)

原文:一步一步写算法(之函数堆栈显示)

【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com 】

在继续图的讨论之前,我们今天开个小差,讨论一下函数堆栈的基本原理。有过编程经验的朋友都知道,堆栈调试是我们在程序开发中经常应用的一个功能。那么大家有没有想过,函数堆栈是怎么开始的啊?其实我们可以自己写一个函数堆栈输出函数分析一下。

因为一般来说,函数的压栈过程是这样的:

|    参数三  |

|    参数二  |

|    参数一  |

|   address|

|      ebp     |

|   variable |     <--------------------------------- ebp

那么堆栈中的内容是怎么打印的呢?

void stack_print()
{
	int var_ebp;

	__asm mov var_ebp, ebp;

	printf("%08x\n", *((int*)(var_ebp) + 1));
}

上面的代码只是打印当前函数的返回地址,那么如果是连续的函数打印呢?打印到main函数开始呢。

void stack_print()
{
	int var_ebp;

	__asm mov var_ebp, ebp;

	do{
        printf("%08x\n", *((int*)(var_ebp) + 1));
        var_ebp = *(int*)(var_ebp);

	}while(var_ebp != 0x0);
}

上面的代码可看到一对地址,那么怎么把这些地址和函数名称对应起来了,那就只能查表了。函数对应的表在哪里呢?不着急,看了下面的一个截图,朋友们就明白怎么回事了。

大家这样在VC编译的时候把Generate mapfile选上,就可以生成对应的*.map文件了。文件中包含了当前文件中主要函数的起始地址,而且是按照从低到高依次排序的。所以只要寻找到对应的函数起始,判断我们的函数返回地址是不是在这个函数中间,那么就可以找到对应的函数名称了。

总结:

(1)今天总结了一下函数堆栈显示的基本原理;

(2)知道函数的基本原理之后,方便我们从本质上理解很多问题。即使很多CPU的处理方式和X86不同,我们也可以通过类似的方法快速掌握;

(3)堆栈原理十分重要,朋友们应该好好了解一下。

时间: 2024-08-09 01:26:49

一步一步写算法(之函数堆栈显示)的相关文章

一步一步写算法(之递归和堆栈)

原文:一步一步写算法(之递归和堆栈) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 看过我前面博客的朋友都清楚,函数调用主要依靠ebp和esp的堆栈互动来实现的.那么递归呢,最主要的特色就是函数自己调用自己.如果一个函数调用的是自己本身,那么这个函数就是递归函数. 我们可以看一下普通函数的调用怎么样的.试想如果函数A调用了函数B,函数B又调用了函数C,那么在堆栈中的数据是怎么保存的呢? 函数A ^ 函数B | (地址递减) 函数C |

一步一步写算法(之字符串查找 上篇)

原文:一步一步写算法(之字符串查找 上篇) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 字符串运算是我们开发软件的基本功,其中比较常用的功能有字符串长度的求解.字符串的比较.字符串的拷贝.字符串的upper等等.另外一个经常使用但是却被我们忽视的功能就是字符串的查找.word里面有字符串查找.notepad里面有字符串查找.winxp里面也有系统自带的字符串的查找,所以编写属于自己的字符串查找一方面可以提高自己的自信心,另外一方面在某

一步一步写算法(之合并排序)

原文:一步一步写算法(之合并排序) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前面一篇博客提到的快速排序是排序算法中的一种经典算法.和快速排序一样,合并排序是另外一种经常使用的排序算法.那么合并排序算法有什么不同呢?关键之处就体现在这个合并上面. 合并算法的基本步骤如下所示: 1)把0~length-1的数组分成左数组和右数组 2)对左数组和右数组进行迭代排序 3)将左数组和右数组进行合并,那么生成的整个数组就是有序的数据数组 下面

一步一步写算法(之排序二叉树)

原文:一步一步写算法(之排序二叉树) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前面我们讲过双向链表的数据结构.每一个循环节点有两个指针,一个指向前面一个节点,一个指向后继节点,这样所有的节点像一颗颗珍珠一样被一根线穿在了一起.然而今天我们讨论的数据结构却有一点不同,它有三个节点.它是这样定义的: typedef struct _TREE_NODE { int data; struct _TREE_NODE* parent; str

一步一步写算法(之单词统计)

原文:一步一步写算法(之单词统计) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 在面试环节中,有一道题目也是考官们中意的一道题目:如果统计一段由字符和和空格组成的字符串中有多少个单词? 其实,之所以问这个题目,考官的目的就是想了解一下你对状态机了解多少. (1) 题目分析 从题目上看,如果对一个字符串进行处理,那么可以有下面几种情形:初始状态,字符状态,空格状态,结束状态.那么这几种状态之间应该怎么迁移呢? 初始状态: 如果输入符号是

一步一步写算法(之寻路)

原文:一步一步写算法(之寻路) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 寻路是游戏设计中需要使用到一种功能,那么我们怎么样以一个点作为起始点,快速地寻找到目标点呢?其实寻路的方法不难.一种简单有效的方法就是回溯法.如果我们从一个点出发,那么这个点周围肯定有若干条路,只要有一条路存在,我们就一直走下去,直到发现没有路走为止:要是发现路走不下去了怎么办,那就只好回头了,我们只能从剩下的选项中继续选择一条路,继续尝试.如果很不幸,所有的

一步一步写算法(之循环单向链表)

原文:一步一步写算法(之循环单向链表) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前面的博客中,我们曾经有一篇专门讲到单向链表的内容.那么今天讨论的链表和上次讨论的链表有什么不同呢?重点就在这个"循环"上面.有了循环,意味着我们可以从任何一个链表节点开始工作,可以把root定在任何链表节点上面,可以从任意一个链表节点访问数据,这就是循环的优势. 那么在实现过程中,循环单向链表有什么不同? 1)打印链表数据 void pri

一步一步写算法(之爬楼梯)

原文:一步一步写算法(之爬楼梯) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前两天上网的时候看到一个特别有意思的题目,在这里和朋友们分享一下: 有一个人准备开始爬楼梯,假设楼梯有n个,这个人只允许一次爬一个楼梯或者一次爬两个楼梯,请问有多少种爬法? 在揭晓答案之前,朋友们可以自己先考虑一下: 这个人爬n层楼梯,那么它也不是一下子就可以爬这么高的,他只有两个选择,要么从n-2层爬过来,要么从n-1层爬过来.除此之外,他没有别的选择.此

一步一步写算法(之非递归排序)

原文:一步一步写算法(之非递归排序) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 在上面一篇博客当中,我们发现普通查找和排序查找的性能差别很大.作为一个100万的数据,如果使用普通的查找方法,那么每一个数据查找平均下来就要几十万次,那么二分法的查找呢,20多次就可以搞定.这中间的差别是非常明显的.既然排序有这么好的效果,那么这篇博客中,我们就对排序算做一个总结. 按照我个人的理解,排序可以分为两种:一种是非递归排序,它主要按照非递归的