__cdecl调用 C语言变参

原创 2011年01月19日 09:52:00

__cdecl调用

在C语言中,函数调用支持不定参数,例如printf函数,可以不知道参数的个数,eg:

void err_info(const char *fmt, ...)

{

va_list ap;

va_start(ap, fmt);

vfprintf(stderr, fmt, ap);

va_end(ap);

}

这是如何实现的呢?如何支持变参的呢?

下面简要介绍下__cdecl调用方式,当然还有很多其他的调用方式,不过目前用不到

函数调用需要关注的几个方面:

1、函数调用时参数是如何保存的?

2、是调用者来清理函数调用还是被调用者来清理函数调用?

3、函数调用时参数的顺序是怎样的?

4、可能会用到哪些寄存器?

先说第一个问题,这个是很容易的,大家都知道C语言中是用栈来保存函数调用时的参数的

下面再分析其他几个问题:

在__cdcel标准中规定:

1、函数调用的参数入栈顺序是从右到左,即先压栈最右边的参数,最后压栈最左边的参数

2、在函数调用结束后用调用者来清理栈

3、调用过程中一般会用到eax、ebx、ecx等寄存器

void func(int a, int b)

{

...

}

int main(void)

{

...

func(1,2);

...

}

下面以这个例子来说明:

在调用的过程中由于是从右到左入栈,所以压栈的顺序是先2后1,用汇编可以描述为:

push 2

push 1

main函数对应的汇编大概是:

push 2

push 1

call func

add esp, 8 //清理栈,因为在调用过程中esp指针向下(或者说是向低地址)移动了8个字节

ret

这是调用顺序上

基于上面的几点我们就可以理解C语言中是如何实现变参函数的调用了:

1、由于函数调用是从右到左入栈的,因此函数调用时最左边的参数是最后一个入栈的,这样就可以函数调用时最左边的参数位置了

2、由于有format的指定,每个参数的大小是可知的,例如%d表示是int型,占用4个字节等

3、根据上面的两项就可以取出函数参数了。首先根据最左边参数(此处的含义是最后一个确定参数,也就是该参数后面的参数都是可变参数)

(例如

void func(char *arg1, char *arg2, ...)

那么最左边的参数意思就是arg2,因为它是最后一个确定参数

)

的位置可以找到函数调用时最左边的参数,然后根据每个参数的大小,移动esp指针(一般是向高地址移动),就可以依次取出其他所有参数了

wiki上介绍:http://en.wikipedia.org/wiki/X86_calling_conventions

clip_image001

clip_image002

clip_image003

关于__stdcall和__cdecl调用方式的理解

__stdcall和__cdecl都是函数调用约定关键字,先给出这两者的区别,然后举实例分析:   __stdcall:参数由右向左压入堆栈;堆栈由函数本身清理。   __cdecl:参数也是...
  • BeanJoy
  • BeanJoy
  • 2013年06月20日 11:46
  • 10204

可变参数的使用-printf简单实现

我们在写一个程序的时候,经常用到一些函数,例如printf函数,在我们用的时候觉得并没有什么觉得他很简单啊,我们使用的时候都没有注意过,它其实有很多种调用方法。 例如: 其实这就是可变...
  • zhouchaoya142526
  • zhouchaoya142526
  • 2017年04月23日 11:20
  • 334

用函数fopen_s打开数据文件

## **用函数fopen_s打开数据文件** ##学习C语言,对文件的输入和输出,打开一个数据文件,一般教材用fopen函数,但是一些编译器编译无法通过,笔者用的Vs2013,提示用fopen_s函...
  • AOBO516
  • AOBO516
  • 2015年06月06日 13:24
  • 8863

strncpy_s

#include "stdafx.h" #include int _tmain(int argc, _TCHAR* argv[]) { int i=0; char ar1[10]...
  • markman101
  • markman101
  • 2010年12月02日 13:35
  • 10191

C语言 变参函数的使用

详细介绍c++中怎样使用变参函数及相关注意事项。
  • aoshilang2249
  • aoshilang2249
  • 2014年07月15日 16:45
  • 1423

关于调用约定(cdecl、fastcall、thiscall)

标 题: 关于调用约定(cdecl、fastcall、thiscall) 作 者: lcx4 时 间: 2016-3-22 链 接: http://www.lcx4.com/?post=...
  • zhuhuibeishadiao
  • zhuhuibeishadiao
  • 2016年04月24日 00:00
  • 249

C++中函数strcpy和strcpy_s(VS pro 2015)

strcpy: 语法: #include char *strcpy( char *to, const char *from ); 功能:复制字符串from 中的字符到字符串to,包括空值结束符...
  • z2014jw
  • z2014jw
  • 2016年02月18日 19:16
  • 6685

GCC Manual

GCC(1)                                GNU                               GCC(1) NAME        gcc...
  • cuiruiqiang
  • cuiruiqiang
  • 2013年12月30日 11:44
  • 2018

visual studio的C/C++修饰名及调用约定(如__cdecl)

程序出链接错误的时候,经常看到lnk errorxxx:某某函数、某某变量找不到等等,里面的函数名通常都很难看明白,因为使用的是修饰名。 C 和 C++ 程序中的函数在内部通过其修饰名加以识别。修饰...
  • J_Jeff
  • J_Jeff
  • 2014年12月03日 10:37
  • 1467

__stdcall 与 __cdecl 区别 (汇编 call ret 时,栈的变化)

__cdecl C++ void fun(int a)   //默认__cdecl {  cout } int main() {  fun(3);  system("pause");  ret...
  • WMJ75617718
  • WMJ75617718
  • 2014年03月17日 00:35
  • 1374
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:__cdecl调用 C语言变参
举报原因:
原因补充:

(最多只允许输入30个字)