可变参数对我多少有点诱惑,当初一开始学习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即可,当然这样的函数也可能没有多大意义,而且可以被随意加个参数替代。
原文链接: https://www.cnblogs.com/20090802/archive/2010/12/30/1921333.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/19461
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!