好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

C调用Lua

C调用Lua

   1. 基础:
    Lua的一项重要用途就是作为一种配置语言。现在从一个简单的示例开始吧。
    --这里是用Lua代码定义的窗口大小的配置信息
    width = 200
    height = 300
    下面是读取配置信息的C/C++代码:   

  1  #include <stdio.h>
  2  #include < string .h>
  3  #include <lua.hpp>
  4  #include <lauxlib.h>
  5  #include <lualib.h>
  6  
  7   void  load(lua_State* L,  const   char * fname,  int * w,  int *  h) {
   8       if  (luaL_loadfile(L,fname) || lua_pcall(L, 0 , 0 , 0  )) {
   9          printf( "  Error Msg is %s.\n  " ,lua_tostring(L,- 1  ));
  10           return  ;
  11       }
  12      lua_getglobal(L, "  width  "  );
  13      lua_getglobal(L, "  height  "  );
  14       if  (!lua_isnumber(L,- 2  )) {
  15          printf( "  'width' should be a number\n  "   );
  16           return  ;
  17       }
  18       if  (!lua_isnumber(L,- 1  )) {
  19          printf( "  'height' should be a number\n  "   );
  20           return  ;
  21       }
  22      *w = lua_tointeger(L,- 2  );
  23      *h = lua_tointeger(L,- 1  );
  24   }
  25  
 26  
 27   int   main()
  28   {
  29      lua_State* L =  luaL_newstate();
  30       int   w,h;
  31      load(L, "  D:/test.lua  " ,&w,& h);
  32      printf( "  width = %d, height = %d\n  "  ,w,h);
  33       lua_close(L);
  34       return   0  ;
  35  }

    下面是针对新函数的解释:
     lua_getglobal 是宏,其原型为: #define lua_getglobal(L,s)  lua_getfield(L, LUA_GLOBALSINDEX, (s)) 。
    每次调用这个宏的时候,都会将Lua代码中与之相应的全局变量值压入栈中,第一次调用时将全局变量"width"的值压入栈中,之后再次调用时再将"height"的值也压入栈中。

     2. table操作:
    我们可以在C语言的代码中操作Lua中的table数据,这是一个非常非常方便且实用的功能。这样不仅可以使Lua代码的结构更加清晰,也可以在C语言代码中定义等同的结构体与之对应,从而大大提高代码的可读性。见如下代码:

  1  #include <stdio.h>
  2  #include < string .h>
  3  #include <lua.hpp>
  4  #include <lauxlib.h>
  5  #include <lualib.h>
  6  
  7   void  load(lua_State*  L) {
   8  
  9       if  (luaL_loadstring(L, "  background = { r = 0.30, g = 0.10, b = 0 }  "  ) 
  10          || lua_pcall(L, 0 , 0 , 0  )) {
  11          printf( "  Error Msg is %s.\n  " ,lua_tostring(L,- 1  ));
  12           return  ;
  13       }
  14      lua_getglobal(L, "  background  "  );
  15       if  (!lua_istable(L,- 1  )) {
  16          printf( "  'background' is not a table.\n  "   );
  17           return  ;
  18       }
  19      lua_getfield(L,- 1 , "  r  "  );
  20       if  (!lua_isnumber(L,- 1  )) {
  21          printf( "  Invalid component in background color.\n  "  );
  22           return  ;
  23       }
  24       int  r = ( int )(lua_tonumber(L,- 1 ) *  255  );
  25      lua_pop(L, 1  );
  26      lua_getfield(L,- 1 , "  g  "  );
  27       if  (!lua_isnumber(L,- 1  )) {
  28          printf( "  Invalid component in background color.\n  "  );
  29           return  ;
  30       }
  31       int  g = ( int )(lua_tonumber(L,- 1 ) *  255  );
  32      lua_pop(L, 1  );
  33  
 34      lua_pushnumber(L, 0.4  );
  35      lua_setfield(L,- 2 , "  b  "  );
  36  
 37      lua_getfield(L,- 1 , "  b  "  );
  38       if  (!lua_isnumber(L,- 1  )) {
  39          printf( "  Invalid component in background color.\n  "  );
  40           return  ;
  41       }
  42       int  b = ( int )(lua_tonumber(L,- 1 ) *  255  );
  43      printf( "  r = %d, g = %d, b = %d\n  "  ,r,g,b);
  44      lua_pop(L, 1  );
  45      lua_pop(L, 1  );
  46       return  ;
  47   }
  48  
 49   int   main()
  50   {
  51      lua_State* L =  luaL_newstate();
  52       load(L);
  53       lua_close(L);
  54       return   0  ;
  55  }

     void lua_getfield(lua_State *L, int idx, const char *k) ; 第二个参数是table变量在栈中的索引值,最后一个参数是table的键值,该函数执行成功后会将字段值压入栈中。
     void lua_setfield(lua_State *L, int idx, const char *k);  第二个参数是table变量在栈中的索引值,最后一个参数是table的键名称,而字段值是通过上一条命令lua_pushnumber(L,0.4)压入到栈中的,该函数在执行成功后会将刚刚压入的字段值弹出栈。
    
    下面的代码示例是在C语言代码中构造table对象,同时初始化table的字段值,最后再将table对象赋值给Lua中的一个全局变量。

  1  #include <stdio.h>
  2  #include < string .h>
  3  #include <lua.hpp>
  4  #include <lauxlib.h>
  5  #include <lualib.h>
  6  
  7   void  load(lua_State*  L) 
   8   {
   9       lua_newtable(L);
  10      lua_pushnumber(L, 0.3  );
  11      lua_setfield(L,- 2 , "  r  "  );
  12  
 13      lua_pushnumber(L, 0.1  );
  14      lua_setfield(L,- 2 , "  g  "  );
  15  
 16      lua_pushnumber(L, 0.4  );
  17      lua_setfield(L,- 2 , "  b  "  );
  18      lua_setglobal(L, "  background  "  );
  19  
 20      lua_getglobal(L, "  background  "  );
  21       if  (!lua_istable(L,- 1  )) {
  22          printf( "  'background' is not a table.\n  "   );
  23           return  ;
  24       }
  25      lua_getfield(L,- 1 , "  r  "  );
  26       if  (!lua_isnumber(L,- 1  )) {
  27          printf( "  Invalid component in background color.\n  "  );
  28           return  ;
  29       }
  30       int  r = ( int )(lua_tonumber(L,- 1 ) *  255  );
  31      lua_pop(L, 1  );
  32      lua_getfield(L,- 1 , "  g  "  );
  33       if  (!lua_isnumber(L,- 1  )) {
  34          printf( "  Invalid component in background color.\n  "  );
  35           return  ;
  36       }
  37       int  g = ( int )(lua_tonumber(L,- 1 ) *  255  );
  38      lua_pop(L, 1  );
  39  
 40      lua_getfield(L,- 1 , "  b  "  );
  41       if  (!lua_isnumber(L,- 1  )) {
  42          printf( "  Invalid component in background color.\n  "  );
  43           return  ;
  44       }
  45       int  b = ( int )(lua_tonumber(L,- 1 ) *  255  );
  46      printf( "  r = %d, g = %d, b = %d\n  "  ,r,g,b);
  47      lua_pop(L, 1  );
  48      lua_pop(L, 1  );
  49       return  ;
  50   }
  51  
 52   int   main()
  53   {
  54      lua_State* L =  luaL_newstate();
  55       load(L);
  56       lua_close(L);
  57       return   0  ;
  58  }

    上面的代码将输出和之前代码相同的结果。
     lua_newtable 是宏,其原型为: #define lua_newtable(L) lua_createtable(L, 0, 0) 。调用该宏后,Lua会生成一个新的table对象并将其压入栈中。
     lua_setglobal 是宏,其原型为: #define lua_setglobal(L,s) lua_setfield(L,LUA_GLOBALSINDEX,(s)) 。调用该宏后,Lua会将当前栈顶的值赋值给第二个参数指定的全局变量名。该宏在执行成功后,会将刚刚赋值的值从栈顶弹出。

     3. 调用Lua函数:
    调用函数的API也很简单。首先将待调用函数压入栈,再压入函数的参数,然后使用lua_pcall进行实际的调用,最后将调用结果从栈中弹出。见如下代码:

  1  #include <stdio.h>
  2  #include < string .h>
  3  #include <lua.hpp>
  4  #include <lauxlib.h>
  5  #include <lualib.h>
  6  
  7   const   char * lua_function_code =  "  function add(x,y) return x + y end  "  ;
   8  
  9   void  call_function(lua_State*  L) 
  10   {
  11       //  luaL_dostring 等同于luaL_loadstring() || lua_pcall()
  12       //  注意:在能够调用Lua函数之前必须执行Lua脚本,否则在后面实际调用Lua函数时会报错,
  13       //  错误信息为:"attempt to call a nil value." 
 14       if   (luaL_dostring(L,lua_function_code)) {
  15          printf( "  Failed to run lua code.\n  "  );
  16           return  ;
  17       }
  18       double  x =  1.0 , y =  2.3  ;
  19      lua_getglobal(L, "  add  "  );
  20       lua_pushnumber(L,x);
  21       lua_pushnumber(L,y);
  22       //  下面的第二个参数表示带调用的lua函数存在两个参数。
  23       //  第三个参数表示即使带调用的函数存在多个返回值,那么也只有一个在执行后会被压入栈中。
  24       //  lua_pcall调用后,虚拟栈中的函数参数和函数名均被弹出。 
 25       if  (lua_pcall(L, 2 , 1 , 0  )) {
  26          printf( "  error is %s.\n  " ,lua_tostring(L,- 1  ));
  27           return  ;
  28       }
  29       //  此时结果已经被压入栈中。 
 30       if  (!lua_isnumber(L,- 1  )) {
  31          printf( "  function 'add' must return a number.\n  "  );
  32           return  ;
  33       }
  34       double  ret = lua_tonumber(L,- 1  );
  35      lua_pop(L,- 1 );  //  弹出返回值。 
 36      printf( "  The result of call function is %f.\n  "  ,ret);
  37   }
  38  
 39   int   main()
  40   {
  41      lua_State* L =  luaL_newstate();
  42       call_function(L);
  43       lua_close(L);
  44       return   0  ;
  45  }

 

分类:  Lua编程

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于C调用Lua的详细内容...

  阅读:50次