C语言/C加加编程新手入门基础学习之函数调用规则

C语言是面向过程的,而C++是面向对象的

C和C++的区别:

C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制)。

C++,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。 所以C与C++的最大区别在于它们的用于解决问题的思想方法不一样。之所以说C++比C更先进,是因为“ 设计这个概念已经被融入到C++之中 ”。

小编推荐一个学C语言/C++的学习裙【 六九九,四七零,五九六 】,无论你是大牛还是小白,是想转行还是想入行都可以来了解一起进步一起学习!裙内有开发工具,很多干货和技术资料分享!

函数的调用规则多数情况下是不需要了解的。但是在跨语言和跨平台编程,比如DLL和COM编程时,就需要了解是怎么回事,因为这涉及到函数参数进出栈的顺序和清理工作。

例如:microsoft的vc默认的是__cdecl方式,而windows API则是__stdcall,如果用vc开发dll给其他语言用,则应该指定__stdcall方式。堆栈由谁清除这个很重要,如果是要写汇编函数给C调用,一定要小心堆栈的清除工作,如果是__cdecl方式的函数,则函数本身(如果不用汇编写)则不需要关心保存参数的堆栈的清除,但是如果是__stdcall的规则,一定要在函数退出(ret)前恢复堆栈。

调用约定(Calling Convention)是指在程序设计语言中为了实现函数调用而建立的一种协议。这种协议规定了该语言的函数中的参数传送方式、参数是否可变和由谁来处理堆栈等问题。不同的语言定义了不同的调用约定。

在C++中,为了允许操作符重载和函数重载,C++编译器往往按照某种规则改写每一个入口点的符号名,以便允许同一个名字(具有不同的参数类型或者是不同的作用域)有多个用法,而不会打破现有的基于C的链接器。这项技术通常被称为名称改编(Name Mangling)或者名称修饰(Name Decoration)。许多C++编译器厂商选择了自己的名称修饰方案。

因此,为了使其它语言编写的模块(如Visual Basic应用程序、Pascal或Fortran的应用程序等)可以调用C/C++编写的DLL的函数,必须使用正确的调用约定来导出函数,并且不要让编译器对要导出的函数进行任何名称修饰。

函数调用规则主要有以下几种:

1、__cdecl

__cdecl调用规则就是C调用规则。按从右至左的顺序压参数入栈,由调用者把参数弹出栈。切记:对于传送参数的内存栈是由调用者来维护的。返回值在EAX中因此,对于象printf这样变参数的函数必须用这种规则。编译器在编译的时候对这种调用规则的函数生成修饰名的饿时候,仅在输出函数名前加上一个下划线前缀,格式为_functionname。

int f(int a,int b);//不加修饰,默认__cdecl调用

int __cdecl f(int a,int b);//明确指出__cdecl调用。

示例程序:

1: #include

2:

3: int __cdecl f(int a,int b)

4: {

5: int c;

6: c = a + b;

7: return c;

8: }

汇编代码如下:注意最后一句ret,后面没有参数。

00401020 push ebp

00401021 mov ebp,esp

00401023 sub esp,44h

00401026 push ebx

00401027 push esi

00401028 push edi

00401029 lea edi,[ebp-44h]

0040102C mov ecx,11h

00401031 mov eax,0CCCCCCCCh

00401036 rep stos dword ptr [edi]

00401038 mov eax,dword ptr [ebp+8]

0040103B add eax,dword ptr [ebp+0Ch]

0040103E mov dword ptr [ebp-4],eax

00401041 mov eax,dword ptr [ebp-4]

00401044 pop edi

00401045 pop esi

00401046 pop ebx

00401047 mov esp,ebp

00401049 pop ebp

0040104A ret

***可变参数函数只能是__cdecl调用规则!***

2、__stdcall

__stdcall也是按从右至左的顺序压参数入栈,但是它是由被调用者把参数弹出栈。_stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,切记:函数自己在退出时清空堆栈,返回值在EAX中。  __stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@”符号和其参数的字节数,格式为_functionname@number。如函数int func(int a, double b)的修饰名是_func@12。

示例程序:

1: #include

2:

3: int __stdcall f(int a,int b)

4: {

5: int c;

6: c = a + b;

7: return c;

8: }

小编推荐一个学C语言/C++的学习裙【 六九九,四七零,五九六 】,无论你是大牛还是小白,是想转行还是想入行都可以来了解一起进步一起学习!裙内有开发工具,很多干货和技术资料分享!

汇编代码如下:注意最后一句ret 8!与__cdecl相比多了个参数8!

00401020 push ebp

00401021 mov ebp,esp

00401023 sub esp,44h

00401026 push ebx

00401027 push esi

00401028 push edi

00401029 lea edi,[ebp-44h]

0040102C mov ecx,11h

00401031 mov eax,0CCCCCCCCh

00401036 rep stos dword ptr [edi]

00401038 mov eax,dword ptr [ebp+8]

0040103B add eax,dword ptr [ebp+0Ch]

0040103E mov dword ptr [ebp-4],eax

00401041 mov eax,dword ptr [ebp-4]

00401044 pop edi

00401045 pop esi

00401046 pop ebx

00401047 mov esp,ebp

00401049 pop ebp

0040104A ret 8

3、__fastcall

__fastcall调用的主要特点就是快,因为它是通过寄存器来传送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈)。__fastcall调用约定在输出函数名前加上一个“@”符号,后面也是一个“@”符号和其参数的字节数,格式为@functionname@number。这个和__stdcall很象,唯一差别就是头两个参数通过寄存器传送。注意通过寄存器传送的两个参数是从左向右的,即第一个参数进ECX,第2个进EDX,其他参数是从右向左的入stack。返回仍然通过EAX..

示例程序:

1: #include

2:

3: int __stdcall f(int a,int b)

4: {

5: int c;

6: c = a + b;

7: return c;

8: }

小编推荐一个学C语言/C++的学习裙【 六九九,四七零,五九六 】,无论你是大牛还是小白,是想转行还是想入行都可以来了解一起进步一起学习!裙内有开发工具,很多干货和技术资料分享!

汇编代码如下,注意比较其与__stdcall和__cdecl在寄存器上的区别。

00401020 push ebp

00401021 mov ebp,esp

00401023 sub esp,4Ch

00401026 push ebx

00401027 push esi

00401028 push edi

00401029 push ecx

0040102A lea edi,[ebp-4Ch]

0040102D mov ecx,13h

00401032 mov eax,0CCCCCCCCh

00401037 rep stos dword ptr [edi]

00401039 pop ecx

0040103A mov dword ptr [ebp-8],edx

0040103D mov dword ptr [ebp-4],ecx

00401040 mov eax,dword ptr [ebp-4]

00401043 add eax,dword ptr [ebp-8]

00401046 mov dword ptr [ebp-0Ch],eax

00401049 mov eax,dword ptr [ebp-0Ch]

0040104C pop edi

0040104D pop esi

0040104E pop ebx

0040104F mov esp,ebp

00401051 pop

这些是C/C++能做的

服务器开发工程师、人工智能、云计算工程师、信息安全(黑客反黑客)、大数据 、数据平台、嵌入式工程师、流媒体服务器、数据控解、图像处理、音频视频开发工程师、游戏服务器、分布式系统、游戏辅助等

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180410A0R8D200?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励