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. 运行phpize失败排查

    ==相关参考== rpm包 http://rpmfind.net/linux/rpm2html/ phpize学习 ==问题及排查过程== 1.phpize失败 2.yum install php-d ...

  2. 【python】Python 3 +pycharm中文支持解决方案

    使用环境:window10 + python 3.5.1 方法:在代码前端增加代码:# -*-coding:gbk-*-

  3. hive 存储格式

    hive有textFile,SequenceFile,RCFile三种文件格式. textfile为默认格式,建表时不指定默认为这个格式,导入数据时会直接把数据文件拷贝到hdfs上不进行处理. Seq ...

  4. Python和VS

    下载VS Code 安装插件Python 安装Python,注意这里需要把Python的目录配置到环境变量中 文档结构非常重要,py文件一定位于根目录,.vscode平级:我曾经因为py文件在.vsc ...

  5. C# and JSON

    JQuery Parse JSON var obj = $.parseJSON(data); C# creates JSON string: public static class JSONHelpe ...

  6. 如何在一整张背景图中,加隐形的a标签

    很常见的一个需求,就上图每个国家图标都得加上各自指定的a标签 这时,我们就可以去加上隐藏且定位准确的几个a标签 这个时候,主要用到的就是text-indent和overflow 这两个属性的配合.te ...

  7. Bootstrap 与 ASP.NET MVC 4 不使用 NuGet Package 笔记

    转自 http://www.mytecbits.com/microsoft/dot-net/bootstrap-with-asp-net-mvc-4-step-by-step 单位最近做了一个Boot ...

  8. vs2015Update2的一个坑

    最近更新了vs2015到update2,然后,蛋疼的事情就来了. 首先发现QT不能用了 boost编译也出问题了 查找了2天,发现问题所在,在于windows sdk更新 10.0.10586.0 了 ...

  9. 背投广告js

    js: $('#appwrap').append('<a href="http://web.2144.cn/gateway/reg?pos=8966" id="ad ...

  10. oracle----复制表中的数据

    两种方法: 1. 在创建表的时候将数据从其他表中复制过来(并且表的结构也复制过来): 语法: CREATE TABLE table_name AS SELECT column1,......|* FR ...