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. 栈(顺序存储)C++模板实现

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

  2. gwt 创建 超链接cell (HyperTextCell)

    package com.cnblogs.hooligen.client; import com.google.gwt.cell.client.AbstractCell; import com.goog ...

  3. 《编写高质量代码:改善Python程序的91个建议》读后感

    编写高质量代码:改善Python程序的91个建议  http://book.douban.com/subject/25910544/ 1.(建议16)is 用于判断两个对象的id是否相等,==才是判断 ...

  4. hdu 4542 小明系列故事——未知剩余系

    小明系列故事——未知剩余系 题意:操作0表示某数有n个约数,操作1为某数有n个非约数:n <= 47777,若是存在小于2^62的数符合,则输出该数,否则若是不存在输出Illegal,若是大于2 ...

  5. hdu 2191 珍惜现在,感恩生活 多重背包入门题

    背包九讲下载CSDN 背包九讲内容 多重背包: hdu 2191 珍惜现在,感恩生活 多重背包入门题 使用将多重背包转化为完全背包与01背包求解: 对于w*num>= V这时就是完全背包,完全背 ...

  6. vim file save as

    the command of vim to save as the file :w new_file_name

  7. Razor语法小记

    1.代码块中,<text>标签用来输出,如: @{ <text>sdfsdf</text> } 输出Html: sdfsdf

  8. js中的ajax的运用

    XMLHttpRequest对象 IE7+,FireFox,Chrome,Opera,Safari创建XHR对象: var xhr=new XMLHttpRequest(); 创建XHR对象的兼容性写 ...

  9. SWFUpload 中文乱码问题

    解决办法:两种: 第一种:把handlers.js的编码方式改为UTF-8(用记事本打开,选择编码格式为utr-8即可) 第二种:在有swfupload控件页面的page_load种加: Respon ...

  10. POJ 2375 Cow Ski Area[连通分量]

    题目链接:http://poj.org/problem?id=2375题目大意:一片滑雪场,奶牛只能向相邻的并且不高于他当前高度的地方走.想加上缆车是的奶牛能从低的地方走向高的地方,求最少加的缆车数, ...