Lua设计小巧很容易与C/C++进行交互,下面我们具体讲解C/C++中如何调用lua,而lua中又如何调用C代码.

首先lua和C交互的一个重要的数据结构lua_State,它是进行数据交换的堆栈,按照严格的LIFO规则(后进先出,始终存取栈顶),lua提供了一些函数来压栈例如:
void   (lua_pushnil) ( lua_State *L );
void   (lua_pushnumber) ( lua_State *L , lua_Number n);
void   (lua_pushinteger) ( lua_State *L , lua_Integer n);
void   (lua_pushlstring) ( lua_State *L , const char *s , size_t l);
void   (lua_pushstring) ( lua_State *L , const char *s );
从函数名称我们可以看出我们可以向栈中压入nil, number, integer, string等类型.
lua还提供了函数,对堆栈进行插入,删除等操作例如:
int    (lua_gettop) ( lua_State *L );
void   (lua_settop) ( lua_State *L , int idx);
void   (lua_pushvalue) ( lua_State *L , int idx);
void   (lua_remove) ( lua_State *L , int idx);
void   (lua_insert) ( lua_State *L , int idx);
void   (lua_replace) ( lua_State *L , int idx);
int    (lua_checkstack) ( lua_State *L , int sz);
函数中的idx参数是数据在栈中的索引,栈中的我们以第一个压入栈中的索引为1,第二个为2,也可以使用负数索引,-1始终表示栈顶的索引,-2表示栈顶下面的第二个元素索引.
lua_gettop函数获取堆栈中元素的个数,也是栈顶元素索引,一个负数索引-x对应于正数索引为gettop-x+1;
lua_settop设置栈顶到指定索引,例如:lua_settop(L, 0)也就是清空堆栈;
lua_remove和lua_insert表示先指定索引插入和删除元素,其他元素作相应移动;
lua_replace从栈顶弹出元素设置到指定的索引位置;
另外我们还可以通过lua_is*一系列函数来检测栈中元素类型,例如:
int  ( lua_isnumber) (lua_State *L, int idx );
int  ( lua_isstring) (lua_State *L, int idx );
int  ( lua_iscfunction) (lua_State *L, int idx );
int  ( lua_isuserdata) (lua_State *L, int idx );
我们可以通过这些函数判断指定索引位置的元素是否是我们期望的类型如:number,string,function等.
好了介绍了这么多函数,我们要实践下写个小程序,实验下各种函数:
#include <stdio.h>
#include <stdlib.h>
 
#ifdef __cplusplus
extern "C" {
#endif
 
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
 
#pragma comment (lib, "lua5.1.lib")
 
#ifdef __cplusplus
}
#endif
 
static int cadd( lua_State *L )
{
    /*lua中调用此函数,参数从栈中弹出 */
    double a = lua_tonumber( L, -2);
    double b = lua_tonumber( L, -1);
 
    lua_pushnumber(L , a + b);
   
    /*返回返回值个数*/
    return 1;
}
 
void load_string (lua_State* L)
{
    /*获取全局变量str,并置于栈顶 */
    lua_getglobal(L , "str");
    if (!lua_isstring (L, -1))
    {
        printf("Get 'str' error, %s\n" , lua_tostring( L, -1));
    }
 
    const char * pstr = lua_tostring(L , -1);
    printf("str : %s\n" , pstr);
   
    /*弹出栈中压入的元素,使栈恢复原来状态 */
    lua_pop(L , 1);
}
 
void load_number (lua_State * L)
{
    /*获取全局变量num,并置于栈顶 */
    lua_getglobal(L , "num");
    if (!lua_isnumber (L, -1))
    {
        printf("Get 'num' error, %s\n" , lua_tostring( L, -1));
    }
 
    double num = lua_tonumber( L, -1);
    printf("num : %lf\n" , num);
   
    lua_pop(L , 1);
}
 
void load_table (lua_State * L)
{
    /*获取全局变量data,并置于栈顶 */
    lua_getglobal(L , "data");
 
    const char * szkey[4] = { "lua", "ruby" , "python", "perl"};
    printf("data = { " );
 
    for (int i = 0; i < 4; ++ i )
    {
        /*在table 在栈顶时,获取 table中key 所对应的value值 ,首先将key 入栈, 此时table位于栈中索引为 ,*/
        /*然后通过调用gettable将 key对应value 压入栈顶, 最后弹出刚才已经读取的元素 ,此时table 重新成为栈顶元素 */
        lua_pushstring(L , szkey[ i]);
        lua_gettable(L , -2);
        printf(" %s = '%s' " , szkey[ i], lua_tostring (L, -1));
        lua_pop(L , 1);
    }
    printf(" }\n" );
 
    lua_pop(L , 1);
}
 
void call_luafunc (lua_State * L)
{
    /*C中调用lua 函数,首先将 lua函数压入栈顶,然后依次压入函数参数 , 函数参数压入从左到右*/
    lua_getglobal(L , "luaadd");
    lua_pushnumber(L , 10);
    lua_pushnumber(L , 20);
    /*保护模式运行luaadd函数 */
    lua_pcall(L , 2, 1, 0);
 
    printf("call luaadd result sum : %lf\n" , lua_tonumber( L, -1));
    lua_pop(L , 1);
}
 
void callback_cfunc (lua_State * L)
{
    lua_getglobal(L , "cfunc");
    lua_pushnumber(L , 10);
    lua_pushnumber(L , 20);
    lua_pcall(L , 2, 1, 0);
 
    printf("call back cadd result sum : %lf\n" , lua_tonumber( L, -1));
    lua_pop(L , 1);
 
}
 
void printtable (lua_State * L)
{
    lua_getglobal(L , "printtable");
 
    /*这里我们new 了一个table然后设置值 ,在lua 中进行打印 */
    lua_newtable(L );
    lua_pushstring(L , "name");
    lua_pushstring(L , "Tom");
    lua_settable(L , -3);
 
    lua_pushstring(L , "age");
    lua_pushstring(L , "20");
    lua_settable(L , -3);
 
    lua_pcall(L , 1, 0, 0);
}
 
int main (void)
{
    lua_State *L = lua_open();
    luaL_openlibs(L );
 
    /*载入lua 文件*/
    luaL_loadfile(L , "test.lua");
    /*这步很重要(test.lua中的 chunk放入堆栈)*/
    lua_pcall(L , 0, 0, 0);
 
    /*从lua 中读取字符串 */
    load_string(L );
    /*从lua 中读取数字类型 */
    load_number(L );
    /*从lua 中读取表类型 */
    load_table(L );
    /*调用lua 中函数*/
    call_luafunc(L );
    /*从lua 调用C函数 */
    callback_cfunc(L );
    /*在C 中建立一个 lua表类型, 在lua中进行打印输出 */
    printtable(L );
 
    lua_close(L );
    return 0;
}
 
--test.lua
str = "This is a string."
num = 22
data = {lua="lua", ruby="ruby", python="python", perl="perl"}

function luaadd(a, b)
        return a + b
end

function cfunc(a, b)
        --回调C中cadd函数,传递a, b两个参数,从左向右压入
        return cadd(a, b)
end

function printtable(t)
        for key in pairs(t) do
                print(key .. ":" .. t[key])
        end
end

 
一.要在C/C++中调用lua我们首先在C/C++中包含下面头文件,如果是C++程序则需要一个宏来保证,编译器生成的函数名按照C语言规则.
#ifdef __cplusplus
extern "C" {
#endif
 
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
 
#pragma comment (lib, "lua5.1.lib")
 
#ifdef __cplusplus
}
#endif
二.我们在main函数中依次调用了一系列函数打开lua环境, 加载标准lua库,然后我们调用luaL_loadfile函数加载一个lua文件,这里只进行了编译lua文中chunk到一个函数中并未进行调用,下面lua_pcall进行调用执行,这步
非常重要,这步就是调用执行编译生成的函数,否则我们后面的调用均不会成功的.另外lua_pcall是从C/C++中调用lua函数,它运行在保护模式,函数调用出错并不会导致程序崩溃,但会返回错误,还有另外一个函数lua_call运行在
非保护模式下.
三.具体函数功能注释已经写的很清楚了,函数调用时参数入栈出栈操作其实和C函数调用时的概念是一致的,明白C语言函数调用的过程,其实很容易理解.
四.lua和C/C++还可以交互userdata类型数据,各种错误处理等这里不再讲述.

lua与C/C++交互的更多相关文章

  1. Lua与C的交互

    Lua 与 C 的交互 Lua是一个嵌入式的语言,它不仅可以是一个独立运行的程序,也可以是一个用来嵌入其它应用的程序库. C API是一个C代码与Lua进行交互的函数集,它由以下几部分构成: 1.  ...

  2. cocos2d-x lua与c++简单交互

    cocos2d-x lua与c++简单交互 version: cocos2d-x 3.6 本文讲述lua与c++的一些简单交互: lua通过消息方式调用c++无参接口 c++调用lua带参接口 1.通 ...

  3. Lua与C/C++交互问题

    初学lua,遇到注册C/C++交互函数问题 在lua与C/C++交互时,C/C++的注册Lua函数若是一个有返回类型(压栈)而不是获取类型的时候应该返回1而不是返回0,否则会出现在Lua中值为nil( ...

  4. Lua与C++的交互

    这篇文章说的挺详细的:Lua与C++的交互

  5. lua与C/C++交互概要

    转 http://blog.csdn.net/wildfireli/article/details/22307635 Lua生来就是为了和C交互的,因此使用C扩展Lua或者将Lua嵌入到C当中都是非常 ...

  6. 通过lua栈了解lua与c的交互

    lua是如何执行的 其中分析.执行部分都是c语言实现的. lua与c的关系 lua的虚拟机是用c语言实现的,换句话说一段lua指令最终在执行时都是当作c语言来执行的,lua的global表,函数调用栈 ...

  7. Lua脚本和C++交互(一)

    现在,越来越多的C++服务器和客户端融入了脚本的支持,尤其在网游领域,脚本语言已经渗透到了方方面面,比如你可以在你的客户端增加一个脚本,这个脚本将会帮你在界面上显示新的数据,亦或帮你完成某些任务,亦或 ...

  8. Lua基本语法-lua与C#的交互(相当简单详细的例子)

    lua脚本 与 C#的交互 本文提供全流程,中文翻译.Chinar坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) 1 Lua And C# -- ...

  9. lua和C++的交互(1)

    /* 以前听的一个故事,当年Java的创造者讲课的时候,一开始先拿一个简单的不能简单的小例子, 不断的扩展,最后成为一个复杂而完美的程序. 一个重要之重要的概念,就是栈.Lua与别的语言交互以及交换数 ...

  10. lua与c的交互(函数专用)

    Lua与C的交互 Lua是一个嵌入式的语言,它不仅可以是一个独立运行的程序,也可以是一个用来嵌入其它应用的程序库. C API是一个C代码与Lua进行交互的函数集,它由以下几部分构成: 1.  读写L ...

随机推荐

  1. Linux – RedHat7 / CentOS 7 忘记root密码修改

    1.(a) 开机出现grub boot loader 开机选项菜单时,立即点击键盘任意鍵,boot loader 会暂停. (b) 按下’e’,编辑选项菜单(c) 移动上下鍵至linux16 核心命令 ...

  2. HTMLImageElement类型的简便利用

    这个是我在复习书籍的时候看见的,当时一个同学想通过页面发送请求,但是数据量不是太大,所以用的get方式,但是页面用表单提交请求的话会让页面进行跳转,当时我在网上查了一点资料,发现基本上都是通过ajax ...

  3. linux系统制作简单流程

    制作嵌入式平台使用的Linux内 核, 方法和制作PC平台 的Linux内 核基本一致, 下面使用 对比的方式介绍如何制作用 于6410开发板的内 核. 1. 清除原有配置与中间文件x86: make ...

  4. 栈(顺序存储)C++模板实现

    #include <iostream> using namespace std; template <typename T> class stack{ private: int ...

  5. npm:Node.js的软件包管理器

    npm https://www.npmjs.com/ 2016-08-03

  6. Transaction的理解

    Transaction的理解   待完善......

  7. 解决MySQL查询不区分大小写

    需要设置collate(校对) . collate规则: *_bin: 表示的是binary case sensitive collation,也就是说是区分大小写的 *_cs: case sensi ...

  8. ios阻止锁屏 --老代码,供参考

    // Disable the idle timer [[UIApplication sharedApplication] setIdleTimerDisabled: YES];    // Or fo ...

  9. 1088-Gnome Sequencing

    描述 In the book All Creatures of Mythology, gnomes are kind, bearded creatures, while goblins tend to ...

  10. Codeforces Round #238 (Div. 1)

    感觉这场题目有种似曾相识感觉,C题还没看,日后补上.一定要坚持做下去. A Unusual Product 题意: 给定一个n*n的01矩阵,3种操作, 1 i 将第i行翻转 2 i 将第i列翻转 3 ...