1.C可变长参数
printf这个使用频繁的C语言函数的参数列表包含一个const char*的描述串,还有一个可变长参数(...) ,如下为printf的函数声明。
int printf(const char * __restrict, ...)
在stdarg.h这个头文件中包含着对可变长参数进行操作的一些宏(x86平台为例):
#define va_start(ap,v)( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap) ( ap = (va_list)0 )
其中运行va_start(ap, v)可以使得ap指向可变长参数列表的第一个参数的地址。其中v为最后一个固定参数。
va_arg(ap,T)使ap指向可变长参数列表的下一个参数,并且用输入的类型T进行数据强转换,返回一个用户需要的参数值。
va_end(ap),置ap为NULL。
详细的可变长参数解释请参见这个博客:
2.C语言对Lua的通用调用函数
1 #include2 3 void call_va(const char * func,const char *sig,...) 4 { 5 va_list vl;//定义一个可变长参数指针,无初始值 6 int narg;//可变长参数的数量 7 int nres;//Lua函数返回值的数量 8 9 va_start(vl,sig);//让指针指向可变长参数的第一个参数首地址10 lua_getglobal(L,func);//函数入栈11 12 //---参数入栈13 for(narg=0;*sig;narg++)//遍历参数14 {15 //检查栈中空间16 luaL_checkstack(L,1,"too many arguments");17 18 switch(*sig++)19 {20 //根据参数的约束符,按类型入栈,d-double i-int s-char*21 case 'd':22 lua_pushnumber(L,va_arg(vl,double));23 break;24 case 'i':25 lua_pushinteger(L,va_arg(vl,int));26 break;27 case 's':28 lua_pushstring(L,va_arg(vl,char*));29 break;30 case '>':31 //输入参数结束32 goto endargs;33 default:34 error(L,"invalid option (%c)",*(sig-1));35 }36 }37 //---参数入栈38 endargs:39 nres=strlen(sig);//期望的Lua函数返回值数量40 41 //调用Lua函数42 if(lua_pcall(L,narg,nres,0)!=0)43 {44 error(L,"error calling '%s':%s",func,lua_tostring(L,-1));45 }46 47 //调用之后的返回值检索48 //栈索引从栈顶往下依次是-1,-2,-3,所以第一个结果的栈索引是-nres49 nres=-nres;50 while(*sig)51 {52 //依次得到返回值的类型描述符 *sig53 switch(*sig++)54 {55 case 'd':56 if(!lua_isnumber(L,nres))57 error(L,"wrong result type");58 *va_arg(vl,double*)=lua_tonumber(L,nres);59 break;60 61 case 'i':62 if(!lua_isnumber(L,nres))63 error(L,"wrong result type");64 *va_arg(vl,int*)=lua_tointeger(L,nres);65 break;66 67 case 's':68 if(!lua_isstring(L,nres))69 error(L,"wrong result type");70 *va_arg(vl,const char**)=lua_tostring(L,nres);71 break;72 73 default:74 error(L,"invalid option (%c)",*(sig-1));75 }76 //结果的参数索引+177 nres++;78 }79 va_end(vl);80 81 }
这样,如果我们需要调用一个lua函数,只需要如下的调用形式:
call_va("func","dd>ds",x,y,&z,&s);
表示这个lua函数的函数名为func,接受两个double,返回一个double和一个字符串,'>'表示参数和返回值结果的分割符。