C/C++,可变参数,va_list,va_start,va_end,va_arg宏的梳理

C/C++;可变参数;va_list;va_start;va_end;va_arg;

pc : 网上相关资料有很多,但是还是想自己的捋一遍

问题分析

如何才能实现可变参数的功能?
1.如何让函数知道参数个数以及参数的数据类型?
2.使用时如何定位这些参数?
3.最好使用时够简洁和方便

在C/C++下如何实现
解决第一个问题,朴实无华的方法就是 用参数样式模板字符串 fmt(format)来指出参数的类型和数量
解决第二个问题前,补充了一下基础内容

基础内容

1.va_list的宏定义

百度词条查说的很清楚(直接引用):

	#ifdef _M_ALPHA
		typedef struct {
			char *a0; /* pointer to first homed integer argument */
			int offset; /* byte offset of next parameter */
		} va_list;
	#else
		typedef char * va_list;
	#endif
	_M_ALPHA是指DEC ALPHA(Alpha AXP)架构。所以一般情况下va_list所定义变量为字符指针。

结论就是:一般情况下va_list就是一个字符指针,除非有定义的_M_ALPHA宏(这并不常见)

2.INTSIZEOF 宏(功能型)
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )	

此宏的作用就是为了求出(栈中参数 数据对齐, 好定位fmt上面的各个参数) :
sizeof(int)(sizeof(int)-1+1)的倍数中sizeof(n)的最小上界(具体可百度:(a+b)&~b)

3.VA_START宏
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )

就是通过const cahr *fmt偏移定位可变参数

4.VA_ARG宏
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

和VA_START宏功能一样*fmt偏移定位下一个可变参数
带来一个问题:这个’t’哪里来,fmt来…emm怎么提取出来的?

5.VA_END宏
#define va_end(ap) ( ap = (va_list)0 ) 

简单明了的宏

资料查找查找我突然明了了,我觉得这几宏做了啥都很明显了
最后还是贴个列子吧:
因为vprint,printf等函数隐藏了对VA_START的使用(所以放弃);
但是我在lua程序设计书里看到了一个有趣的使用方法
(请关注重点,lua程序细节无视就好):

//调用样式:
double x,y,z;
call_val(L,"oneFun","dd>d",x,y,&z)

//
void call_va(lua_State* L, const char * fun,  const char *sig, ...)
{
	va_list vl;
	int narg, nres;
	
	//这里sig就是上边提到的  'fmt'
	va_start(vl, sig);
	
	//先将函数入栈
	lua_getglobal(L, fun);

	//压入参数 并计数
	for (narg = 0; *sig; narg++)
	{
		luaL_checkstack(L, 1, "too many argnment");
		switch (*sig++) {
		case 'd' :
			lua_pushnumber(L, va_arg(vl, double));
			break;
		case 'i':
			lua_pushinteger(L, va_arg(vl, int));
			break;
		case 's':
			lua_pushstring(L, va_arg(vl, char*));
			break;
		case '>':
			goto endarge;
		default:
			error(L, "invalid opint(%c)", *(sig - 1));
		}
	}
	endarge:

	nres = strlen(sig); 

	//运行函数
	if (lua_pcall(L, narg, nres, 0) != LUA_OK)
		error(L, "error calling '%s' : '%s' ", fun, lua_tostring(L, -1));

	//获取结果
	nres = -nres; 
	while (*sig)
	{
		switch (*sig++)
		{
		case 'd':
		{
			int isnum;
			double n = lua_tonumberx(L, nres, &isnum);
			if (!isnum)
				error(L, "wrong result type");

			*va_arg(vl, double*) = n;
			break;
		}
		case 'i':
		{
			int isnum;
			int n = lua_tointegerx(L, nres, &isnum);
			if (!isnum)
				error(L, "wrong result type");
			*va_arg(vl, int*) = n;
			break;
		}
		case 's':
		{
			const char* s = lua_tostring(L, nres);
			if (s == NULL)
				error(L, "wrong result type ");
			*va_arg(vl, const char**) = s;
			break;
		}
		default:
			error(L, "invalid option (%c)", *(sig-1));
		}
		nres++;
	}
	va_end(vl);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值