zoukankan      html  css  js  c++  java
  • C 可变长参数运用-----编写Lua的通用调用函数

    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。

    详细的可变长参数解释请参见这个博客:imjacob的专栏——c语言中的printf实现

    2.C语言对Lua的通用调用函数

     1 #include <stdarg.h>
     2 
     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,所以第一个结果的栈索引是-nres
    49     nres=-nres;
    50     while(*sig)
    51     {
    52         //依次得到返回值的类型描述符 *sig
    53         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         //结果的参数索引+1
    77         nres++;
    78     }
    79     va_end(vl);
    80 
    81 }

    这样,如果我们需要调用一个lua函数,只需要如下的调用形式:

    call_va("func","dd>ds",x,y,&z,&s); 

    表示这个lua函数的函数名为func,接受两个double,返回一个double和一个字符串,'>'表示参数和返回值结果的分割符。

  • 相关阅读:
    安装mongodb,开启mongo服务,创建mongodb用户,登陆mongodb
    【Flask】bootstrap table基础
    【网络安全】加解密算法最详解
    UAC table
    Docker的部署安装(CentOS)-by paymob
    Docker中运行MySQL5.7并挂载宿主机目录到镜像
    搭建harbor企业级私有registry
    Rancher的部署安装(编排选用K8S)
    使用Rancher pipeline搭建基于容器的CICD
    Docker的部署安装(CentOS)
  • 原文地址:https://www.cnblogs.com/kyokuhuang/p/4418416.html
Copyright © 2011-2022 走看看