20190304 工作记录

1.map value可重复

2.  运行时错误

The value of ESP was not properly saved across a function call.
This is usually a result of calling a function declared
with one calling convention with a function pointer declared with
a different calling convention

错误的原因是声明相应的函数未匹配。函数定义的调用规则,和实际的调用规则不同

极有可能是其中一个函数指针有问题

编译器默认是__cdecl,而函数指针是由void*传进去的__stdcall方式,由于

编译时不会报错,结果出现运行时错误。

3. __stdcall和__cdecl  

     函数调用时需要用到栈,当函数调用完成后,栈需要清除,这里就是关键问题

如何清除??

   使用__cdecl,那么栈的清除工作是由调用者完成,这样带来一个棘手的问题

不同的编译器产生栈的方式不尽相同,那么调用者能否正常的完成清除工作呢?
答案是不能

    使用__stdcall,上边的问题就解决了,函数自己决绝清除工作

所以在跨平台开发中,我们都是用__stdcall

   那问什么还需要__cdecl呢??当遇到函数如fprintf他的参数时可变的

不定长的,调用者事先无法知道参数的长度,事后的清除工作也无法正常进行

这种情况只能使用__cdecl。
       结论:如果程序中没有涉及可变参数,最好使用__stdcall

4.__stdcall

在C语言中,假设我们有这样的一个函数:

int function(int a,int b)

调用时只要用result = function(1,2)这样的方式就可以使用这个函数

但是,当高级语言被编译成计算机可识别的机器码时,有一个问题就凸显出来

在cpu中,计算机没办法知道一个函数需要多少个、什么样的参数,也没有硬件可以保存这些参数

也就是说,计算机不知道怎么给这个函数传递参数,传递参数的工作必须由调用者和函数本身来协调

为此,计算机提供了一种被称为栈的数据结构来支持参数传递

   栈是一种先进后出的数据结构,栈有一个存储区、一个栈顶指针。栈顶指针指向堆栈中第一个可用的数据项(被称为栈顶)。用户可以在栈顶上方向栈中加入数据,这个操作被称为压栈(Push),压栈以后,栈顶自动变成新加入数据项的位置,栈顶指针也随之修改。用户也可以从堆栈中取走栈顶,称为弹出栈(pop),弹出栈后,栈顶下的一个元素变成栈顶,栈顶指针随之修改
      函数调用时,调用者依次 把参数 压栈,然后调用函数,函数被调用以后,在堆栈中

取得数据,并进行计算。函数计算结束后,或者调用者或者函数本身修改堆栈,时堆栈恢复原状

5.

在参数传递中,有两个很重要的问题必须得到明确说明:

    当参数个数多于一个时,按照什么顺序把参数压入堆栈

    函数调用后,由谁来把堆栈恢复原装

    在高级语言中,通过函数调用约定来说明这两个问题。常见的调用约定有:

stdcall的调用约定意味着:1)参数从右向左压入堆栈,2)函数自身修改堆栈 3)函数名自动加前导的下划线,后面紧跟一个@符号,其后紧跟着参数的尺寸

基本概念:

(1)ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。

(2)EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。

猜你喜欢

转载自blog.csdn.net/weixin_38756546/article/details/88104955