沧桑不尽
无穷的沧桑,不尽的落叶

可变参数对我多少有点诱惑,当初一开始学习C的时候,就被它迷惑了,我自己写的函数都是定参的,当时以我的功力,断是费上三天三夜功夫也搞不定可变参数。

在汇编的课开完之后,其实对c的一些技巧已经不稀奇了,C毕竟是C,而不像C++有太多的语法规定和编译器规定。

 

昨天头热,想再来看看这个变参,也许可以偶尔在工作上用一下。

参数是靠堆栈来保存的,其实看看堆栈就知道怎么来获取的了,那获取变参应该就简单了:1.在堆栈中获取数据2.将这些数据转换成参数的值。

 

加之C中已经有人做了这么几个宏:

代码
#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end

/* A guess at the proper definitions for other platforms */

#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )

#define _ADDRESSOF(v) ( &(v) )
对于这些宏,对于不同的平台定义是不一样的,但作用都是一样一样的。

我写了几行代码看了下堆栈

代码
#include "stdafx.h"
#include
<stdarg.h>
void f(int n,...)
{
va_list arglist;
va_start(arglist,n);
int nArg = va_arg(arglist,int);
va_end(arglist);
}

int _tmain(int argc, _TCHAR* argv[])
{
f(
1,1,0x2);
}
断点到f函数被调用那行,转到汇编下,可看到参数的入栈顺序,当然这里的调用约定是__cdecl,慢慢压栈,观察栈的变化,然后在跟踪进f看参数怎么出栈的。

其实一般可变参数不需要栈的,但是如果一个函数连一个定参都没有的话,那就不行的了va_的几个宏只能是根据最后一个定参的地址确定其他的地址的,如果没有一个定参,那么这几个宏,将无用武之地了,这个时候,可以直接在f中获取寄存器的esp即可,当然这样的函数也可能没有多大意义,而且可以被随意加个参数替代。

 

posted on 2010-12-30 09:03  沧桑不尽  阅读(343)  评论(2编辑  收藏  举报