怎么知道函数画图c++有什么函数可以用

这篇文章的内容是一个老生常谈的问题----& 函数是如何被调用的。
本文用汇编代码研究函数调用的过程,参数调用的方式,函数值的返回。
1. 函数是如何实现调用的
&&& 函数的调用是用call 和 ret 指令实现的。这里首先简单说明下这call指令的作用:call指令与跳转指令相似,但是不同的是保持返回信息, 即将下一个指令入栈,当遇到ret的时候,返回到这个地址。
&& &呵呵,有点抽象, 下面就用实例来说明,我们写下如下代码:
1 int add(int a, int b) 2 { 3
return a+b; 4 } 5
6 &int _tmain(int argc, _TCHAR* argv[]) 7 { 8
int a(1), b(2); 9
b = add(a,b);10
return 0;11 }
&& &很简单的代码,这里我们关注的是add函数是如何被调用的,下面我们看下其汇编代码的实现
1 //int a(1), b(2); 2 &004113FE mov
dword ptr [a],1 3 & mov
dword ptr [b],2 4 &//b = add(a,b); 5 &0041140C mov
eax,dword ptr [b] 6 0041140F push
eax 7 & mov
ecx,dword ptr [a] 8 & push
add (41109Bh)10 & add
esp,811 0041141C mov
dword ptr [b],eax12 &//return 0;13 &0041141F xor
&& &如上,红色的部分为调用的add函数的代码, 当调用add函数时相关寄存器的情况是
&& & & &EIP = 0041109B
&& & & &ESP = 0012FE78
&& & & &EBP = 0012FF68
&& &其中EIP是下一个指令的地址,而ESP就是保存了add函数的地址了。我们看以在memory窗口看下其值:
&& & & &0x0012FE78 & & 19 14 41 00
&& &根据小字节存储顺序 其值应该为 , 刚好为下一个指令的地址。
&& &再来看下add函数内部的调用情况:
1 int add(int a, int b)2 {3
ebp,esp5 &//&&一大堆对esp的操作6 & mov
ebp8 004113CA ret9 }
&& &这里我们需要注意的是 如上列出的指令就是所谓的堆栈平衡。首先ebp入栈, 然后把esp的值赋给ebp, 中间有一大堆对esp的操作, 最后把ebp的刚才保存的值赋给esp, ebp出栈。这样做的原因是为了中间对栈的操作不影响ebp的值,当函数返回时,其值依旧是刚进入此函数的ebp的值。
2. 函数参数的调用方式
&& &一.堆栈方式
&& &二.寄存器方式
&& &三.全局变量
2.1 堆栈方式
&& &如果函数通是堆栈方式的调用就必须要做如下两个方面:
&& & & &1. 对应堆栈的顺序
&& & & &2. 由谁来平衡堆栈(调用者还是子程序)
&& &所以我们必须约定函数参数调用的方式。常见的调用约定由如下几个:
_cdecl(C/C++的默认方式)
Stdcall(win32 API的默认方式)
参数传递顺序
平衡堆栈着
&&& 在这里我们看下_cdecl调用时如何实现的。还是本文的第一段代码,这里我们只观察其参数的传递:
1 0041140C mov
eax,dword ptr [b]2 0041140F push
// ESP = 0012FE843 & mov
ecx,dword ptr [a]4
add (41109Bh) //ESP = 0012FE7C6
//ESP = 0012FE84
&& &如上, 首先push b, 然后push a, 一切执行完之后在
&& &这里需要指出的一点是栈是向下增长的,也就是说每一次push的时候,ESP的值会减少。
2.2 寄存器方式
&& &寄存器传递函数参数的方式没有一个统一的标准,所以不同编译器的实现各有不同。这里只选取MSVC来说明。让在MSVC中采用_fasetcall来传递参数是,最左边的不大于4字节的参数分别放在ecx和edx中,寄存器用完以后就按照从右到左的顺序人栈。
我们可以看下如下的例子:
1 int _fastcall add(int a, int b, int c) 2 { 3 return a+b; 4 } 5
6 int _tmain(int argc, _TCHAR* argv[]) 7 { 8 int a(1), b(2),c(3); 9 c = add(a,b,c);10 return 0;11 }
下面再来看下汇编代码
1 004113FE mov
dword ptr [a],1 2
dword ptr [b],2 3 0041140C mov
dword ptr [c],3 4 // c = add(a,b,c); 5
dword ptr [c] 6
//第三个参数,入栈 7
edx,dword ptr [b] //第二个参数,放入edx中 8 0041141A mov
ecx,dword ptr [a] //第一个参数,放入ecx中 9 0041141D call
add (4111D1h)10
dword ptr [c],eax
&& &如上,我们可以比较出参数调用的不同。其调用时第一个参数是放在ecx中,第二个参数是放入edx中。
3. 函数的返回值
&& &函数的返回方式有两种:
&& & & &1.& Return 直接返回
&& & & &2.& 以引用方式返回
&& &第一种方式,函数的返回值是放在eax中的,如果返回值的长度大于32,其高位会放在eax中。这个比较简单,这里不着重讨论。
&& &我们这里着重看的是以引用方式返回, 我们敲下如下代码:
1 void swap(int& a, int& b) 2
int tmp = 4
int _tmain(int argc, _TCHAR* argv[]) 9
int a(1), b(2);11
swap(a,b);12
return 0;13 }
&& &然后我们再来看其汇编对于add函数的实现:
1 0041140C
eax,[b] //压地址入栈 2 0041140F
swap (4111D6h)
//int tmp = 9 004113BE
eax,dword ptr [a] 10
ecx,dword ptr [eax] 11
dword ptr [tmp],ecx 12
eax,dword ptr [a] 14
ecx,dword ptr [b] 15 004113CC
edx,dword ptr [ecx] 16 004113CE
dword ptr [eax],edx //指针的地址改变了17
eax,dword ptr [b] 19
ecx,dword ptr [tmp] 20
dword ptr [eax],ecx21
&& &如上, 以16 行为列, 引用来作为函数的参数只是用地址来代替普通的值, 其他和一般值参数没有区别。
阅读(...) 评论()当前位置:
> 关于C++中定义比较函数的三种方法小结
关于C++中定义比较函数的三种方法小结
下面小编就为大家带来一篇关于C++中定义比较函数的三种方法小结。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
C++编程优与Pascal的原因之一是C++中存在STL(标准模板库)。STL存在很多有用的方法。
C++模板库中的许多方法都需要相关参数有序,例如Sort()。显然,如果你想对一个集合进行排序,你必须要知道集合中的对象,那个在前那个在后。因此,学会如何定义比较方法是非常重要的。
C++模板库的许多容器需要相关类型有序,例如set&T& 和priority_queue&T&。
这篇文章旨在告诉大家如何为一个类定义一个排序方法,以便在STL容器或者方法中使用。 作为一个C++程序员,你应该知道这些方法。
如何定义排序?
简而言之,为一个类定义排序,我们就可以知道类的任意两个对象在排序的过程中谁在前谁在后。我们可以用一个方法来实现,这个方法返回一个bool值表示谁排在前面。显然,我们希望实现一个类似,f(x,y),这种形式的方法。它接收同一类型的对象作为两个参数,返回值则表明谁会出现在谁前面。
严格弱序化
几乎所有的方法或容器都需要排序来满足数学意义上的标准严格弱序化,否则这些方法或容器的行为将不可预知。
假设f(x,y)是一个比较函数。 如果该函数满足如下条件则它是严格弱序化的。
1.f(x,x) =
2. if f(x,y) then !f(y,x)
3.if f(x,y) and f(y,z) then f(x,z)
4. if !f(x,y)&&!f(y,x) then x==y; if x==y and y==z then x==z;
看上去有点晕乎,不过不用担心,只要你的比较方法能够满足对相等元素永远返回false,那你的方法就满足要求了。
三种实现方式:
1. 定义 & 操作符。
&使用这种方法可以使我们自定义的类能够获得与生俱来的排序能力。例如,如果有如下类:
struct Edge
int from,to ,
因为要实现Kruskai算法,你希望图中的所有边依据权重按降序排列。 像这样来定义 operator&:
struct Edge
int from,to ,
bool operator &(Edge other) const
return weight&other.
你定义的方法必须按照如下方法声明:
bool operator& (T other) const
注意: const关键字是必须的。
如果你不喜欢这种方式,比如,明明是要比较两个对象,方法却只有一个参数。你可以选择如下方式:
struct Edge
  int from,
  friend bool operator&(Edge a,Edge b)
    return a.weight&b.
STL的pair&T1,T2&就具有与生俱来的排序能力。两个pair对象的比较这样的:先比较第一个参数,如果第一个参数相同再比较第二个参数。
所有内置类型都具有与生俱来的排序能力,这是由编译器赋予的。
2. 自定义排序方法。
使用这种方式常常用在如下情形:
a.比较内置类型
b.不能修改需要比较的类型
c.除了类型自定义的比较方式以外的比较方法
简单来说,一个比较方法接收两个同类型的对象作为参数并且返回一个bool值,原型如下:
bool name(T a,T b);
3. 重载()操作符
我们可以将比较函数作为STL容器构造函数的第一个参数,并且把函数类型作为模板参数。例如:
set&int,bool (*)(int,int)& s(cmp);
这样做或多或少会让人费解。那我们就来看看如何使用仿函数来消除你的疑惑吧。
我们需要定义一个新的类并重载()操作符。
vector&int&
struct cmp
bool operator()(int a, int b)
return occurrences[a] & occurrences[b];
现在我们就可以把这个类作为模板参数传递给STL容器了。
set&int, cmp&
priority_queue&int, vector&int&, cmp&
STL也有一些内置的仿函数,例如less&T&,greater&T&等。
仿函数可以通过初始化然后像普通函数一样使用。最简单的就是在仿函数后面加上()。
sort(data.begin(), data.end(), greater&int&());
以上就是小编为大家带来的关于C++中定义比较函数的三种方法小结全部内容了,希望大家多多支持IT工厂~
上一篇: 下一篇:如何应用C++的函数对象
作者:类型:转载 时间: 21:09:13
前言C++函数对象是通过一张虚函数表来实现的。简称为V-Table。在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、重载的问题,保证其容真实反应实际的函数。应用假如我们实现了这样的一个单向链表:class LinkedListNode { int data_; LinkedListNode *next_;};class LinkedList { public: void insert(LinkedListNode* &p); void del(LinkedListNode *p); private: LinkedListNode *head_;};其中insert将p插入到head_为头指针的链表中,而p对应的内存由外面分配好,调用的时候类似于这样:LinkedLLinkedListNode *p = new LinkedListNode(2, NULL);list.insert(p);其中,p可能是通过new得到,也可能是malloc出来。好,问题来了:这个类的del函数应该如何实现呢?如果节点是new出来的,我们得delete;如果是malloc出来的,我们得使用配套的free。否则,行为就是undefined。而且,用户还可能实现了自己的定制的内存分配回收例程。我们并不知道该内存是如何分配得到的。这就是问题所在。解决方法是让用户将正确的、对应的、适配的资源释放例程传递进来,然而delete是expression,free是函数,更悲剧的是不同用户实现的资源回收函数原型不尽相同。如何做呢?函数对象是解决这个问题的利器。我们可以这样:template&typename CallBack&class LinkedList{ public: void insert(LinkedListNode* &p); void del(LinkedListNode *p); private: LinkedListNode *head_;};在del中:void del(LinkedListNode *p){ //... LinkedListNode *prev = get_prev(p); prev-&next_ = p-&next_; CallB cb(p);//调用用户提供的资源回收例程}用户需要实现自己的CallBack类的operator()成员函数。如下所示:class MyReclaimRoutine { public: void operator() (LinkedListNode *p) { //free(p) ? my_release_func(p) ? all up to you! } };然后就万事大吉了:LinkedList&MyReclaimRoutine&LinkedListNode *p = new LinkedListNode(2, NULL);list.insert(p);list.del(p);//ok! delete p will be called总结以上就是C++函数对象的应用的全部内容,希望本文的内容对大家学习C++的函数对象能有所帮助,如果有疑问欢迎大家留言讨论。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
网络推荐的内容}

我要回帖

更多关于 知道偏导数求原函数 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信