Lua

≯℡__Kan透↙ 提交于 2020-04-06 17:49:56

Lua扩展c程序

api

出入栈api

  • push 系列 (C -> Stack)

    void lua_pushnil (lua_State * L);
    void lua_pushboolean (lua_State * L, int bool);
    void lua_pushnumber (lua_State * L, lua_Number n); // double
    void lua_pushinteger (lua_State * L, lua_Integer n); // integer
    void lua_pushlstring (lua_State * L, const char * s, size_t len);
    void lua_pushstring (lua_State * L, const char * s);
    
  • set 系列 (Stack -> Lua)

    void lua_setglobal(lua_State * L, const char * name);
    void lua_settable(lua_State * L, int idx);
    void lua_setfield(lua_State * L, int idx, const char * k);
    void lua_seti(lua_State * L, int idx, lua_Integer n);
    void lua_rawset(lua_State * L, int idx);
    void lua_rawseti(lua_State * L, int idx, lua_Integer n);
    void lua_rawsetp(lua_State * L, int idx, const void * p);
    int  lua_setmetatable(lua_State * L, int objindex);
    void lua_setuservalue(lua_State * L, int idx);
    
  • get 系列 (Lua -> Stack)

    int lua_getglobal(lua_State *L, const char *name);
    int lua_gettable(lua_State *L, int idx);
    int lua_getfield(lua_State *L, int idx, const char *k);
    int lua_geti(lua_State *L, int idx, lua_Integer n);
    
    int lua_rawget(lua_State *L, int idx);
    int lua_rawgeti(lua_State *L, int idx, lua_Integer n);
    int lua_rawgetp(lua_State *L, int idx, const void *p);
    
    void 	lua_createtable(lua_State *L, int narr, int nrec);
    void* 	lua_newuserdata(lua_State *L, size_t sz);
    int 	lua_getmetatable(lua_State *L, int objindex);
    int 	lua_getuservalue(lua_State *L, int idx);
    

获取栈元素

  • _is 和 _to 系列,不会出栈。

    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_isinteger(lua_State *L, int idx);
    int 		lua_isuserdata(lua_State *L, int idx);
    int 		lua_type(lua_State *L, int idx);
    const char* lua_typename(lua_State *L, int tp);
    
    lua_Number 		lua_tonumberx(lua_State *L, int idx, int *isnum);
    lua_Integer 	lua_tointegerx(lua_State *L, int idx, int *isnum);
    int 			lua_toboolean(lua_State *L, int idx);
    const char* 	lua_tolstring(lua_State *L, int idx, size_t *len);
    size_t 			lua_rawlen(lua_State *L, int idx);
    lua_CFunction 	lua_tocfunction(lua_State *L, int idx);
    void* 			lua_touserdata(lua_State *L, int idx);
    lua_State* 		lua_tothread(lua_State *L, int idx);
    const void* 	lua_topointer(lua_State *L, int idx);
    
  • check 系列

    // 检查函数的第 arg 个参数是否是一个 数字,并返回这个数字
    lua_Number luaL_checknumber(lua_State *L, int arg);
    // 检查函数的第 arg 个参数是否是一个 字符串并返回这个字符串
    const char *luaL_checkstring (lua_State *L, int arg);
    

栈管理api

  • 常用宏函数

    // 弹出栈顶 n 个元素
    #define lua_pop(L,n) lua_settop(L, -(n) - 1)
    // 移除栈中索引"index"处的元素, 该元素之上的所有元素下移
    #define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1))
    // 将栈顶元素移动到索引"index"处, 索引"index"(含)之上的所有元素上 上移
    #define lua_insert(L,idx) lua_rotate(L, (idx), 1)
    
  • 为发防止进栈溢出, 有如下函数可用

    int  lua_checkstack (lua_State *L, int sz);
    void luaL_checkstack (lua_State *L, int sz, const char *msg);
    
  • 基本函数

    // 返回栈顶元素的索引。因为栈中元素的索引是从 1 开始编号的, 所以函数的返回值相当于栈中元素的个数。返回值为 0 表示栈为空。
    int lua_gettop(lua_State *L);
    //设置栈顶为索引"index"指向处。如果"index"比"lua_gettop()"的值大, 那么多出的新元素将被赋值为"nil"。lua_settop(L, 0); 清空栈。
    void lua_settop(lua_State *L, int index);
    // 将索引"index"处元素, 压到栈顶。(把栈上给定索引处的元素作一个副本压栈)
    void lua_pushvalue (lua_State *L, int index);
    // 将栈顶元素拷贝到索引"index"处。(栈顶出栈,覆盖了索引"index"处的元素)
    void lua_replace(lua_State *L, int index);
    // 把从 从 idx  开始到栈顶的元素 轮转 n 个位置。
    void lua_rotate (lua_State *L, int index, int n);
    

数据类型宏

  • Lua基本数据类型

    #define LUA_TBOOLEAN 		1
    #define LUA_TLIGHTUSERDATA 	2
    #define LUA_TNUMBER 		3
    #define LUA_TSTRING 		4
    #define LUA_TTABLE 			5
    #define LUA_TFUNCTION 		6
    #define LUA_TUSERDATA 		7
    #define LUA_TTHREAD 		8
    

测试

extern "C"{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}

void stackDump(lua_State *L) {
    int count = 0;
    printf("begin dump lua stack %d\n", count);
    
    int top = lua_gettop(L);
    for (int i=1; i <= top; ++i) {
        int t = lua_type(L, i);
        switch (t)
        {
        case LUA_TSTRING:
            printf("'%s'\n", lua_tostring(L, i));
            break;
        case LUA_TBOOLEAN:
            printf(lua_toboolean(L, i) ? "true\n" : "false\n");
            break;
        case LUA_TNUMBER:
            printf("%g\n", lua_tonumber(L, i));
            break;
        default:
            printf("%s\n", lua_typename(L, t));
            break;
        }
    }
}

int main(int argc, char **argv) {
    printf("%s\n",argv[0]);

    lua_State *L = luaL_newstate();
    luaL_openlibs(L);

    stackDump(L);

    lua_pushinteger(L, 1);
    lua_pushinteger(L, 2);
    lua_pushinteger(L, 3);
    lua_pushinteger(L, 4);
    stackDump(L);

    int n = lua_gettop(L);
    printf("stack size = %d\n", n);

    //lua_settop(L, 2);
    //stackDump(L);

    // lua_pop(L, 1);
    //lua_pushvalue(L, 2);
    lua_replace(L, 1);
    stackDump(L);

    // lua_rotate(L, 1, -1);
    lua_insert(L, -2);
    stackDump(L);

    luaL_dofile(L, "test.lua");
    lua_close(L);
    return 0;
}
/* output
    ./build/main
    begin dump lua stack 0
    begin dump lua stack 0
    1
    2
    3
    4
    stack size = 4
    begin dump lua stack 0
    4
    2
    3
    begin dump lua stack 0
    4
    3
    2
    test lua...
*/

Lua扩展C

访问Lua全局变量

int lua_getglobal (lua_State *L, const char *name);
// 将 lua 全局作用域中变量名为 name 的成员压入虚拟栈中

测试:

test.lua

price = 9999
name = "kirito"

c

extern "C"{
#include  <lua.h>
#include  <lualib.h>
#include <lauxlib.h>
}

void stackDump(lua_State *L) {
    int count = 0;
    printf("begin dump lua stack %d\n", count);
    
    int top = lua_gettop(L);
    for (int i=1; i <= top; ++i) {
        int t = lua_type(L, i);
        switch (t)
        {
        case LUA_TSTRING:
            printf("'%s'\n", lua_tostring(L, i));
            break;
        case LUA_TBOOLEAN:
            printf(lua_toboolean(L, i) ? "true\n" : "false\n");
            break;
        case LUA_TNUMBER:
            printf("%g\n", lua_tonumber(L, i));
            break;
        default:
            printf("%s\n", lua_typename(L, t));
            break;
        }
    }
}

int main(int argc, char **argv) {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    int ret = luaL_dofile(L, "test2.lua");
    printf("ret = %d\n", ret);

    lua_getglobal(L, "price");
    int price = lua_tointeger(L, -1);
    printf("price = %d\n", price);

     lua_getglobal(L, "name");
    const char  *name  = lua_tostring(L, -1);
    printf("name = %s\n", name);

    stackDump(L);

    lua_pop(L, 2);
    stackDump(L);


    lua_close(L);
    return 0;
}
/*
ret = 0
price = 9999
name = kirito
begin dump lua stack 0
9999
'kirito'
begin dump lua stack 0
*/

访问Lua全局表字段

void lua_gettable (lua_State *L, int index);
// 把 t[k] 值压入堆栈,这里的 t 是指有效索引 index 指向的值,而 k 则是栈顶放的值。
// 这个函数会弹出堆栈上的 key,把结果放在栈上原来 key 的相同位置。

int lua_getfield (lua_State *L, int index, const char *k);
// lua_getfield(stack, -1, "loaded");
// 等 价 于 lua_pushstring(L, "loaded"), lua_gettable(L, -2);

测试:

test.lua

mytab = {price = 9999, name = "kirito"}

c

extern "C"{
#include  <lua.h>
#include  <lualib.h>
#include <lauxlib.h>
}

void stackDump(lua_State *L) {
    int count = 0;
    printf("begin dump lua stack %d\n", count);
    
    int top = lua_gettop(L);
    for (int i=1; i <= top; ++i) {
        int t = lua_type(L, i);
        switch (t)
        {
        case LUA_TSTRING:
            printf("'%s'\n", lua_tostring(L, i));
            break;
        case LUA_TBOOLEAN:
            printf(lua_toboolean(L, i) ? "true\n" : "false\n");
            break;
        case LUA_TNUMBER:
            printf("%g\n", lua_tonumber(L, i));
            break;
        default:
            printf("%s\n", lua_typename(L, t));
            break;
        }
    }
}

int main(int argc, char **argv) {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    int ret = luaL_dofile(L, "test3.lua");
    printf("ret = %d\n", ret);

    lua_getglobal(L, "mytab");

    // lua_pushstring(L, "price"); //-1 -2
    // lua_gettable(L, ,  -2);
    lua_getfield(L, -1, "price");
    int price = lua_tonumber(L, -1);  //将  k=price  替换成了 v =  9999
    printf("price = %d\n", price);

    stackDump(L);

    lua_settop(L, 1);
    lua_getfield(L, -1, "name");
    const char *name = lua_tostring(L, -1);
    printf("name = %s\n", name);

    stackDump(L);

    lua_pop(L, 2);
    stackDump(L);


    lua_close(L);
    return 0;
}

/*
ret = 0
price = 9999
begin dump lua stack 0
table
9999
name = kirito
begin dump lua stack 0
table
'kirito'
begin dump lua stack 0
*/

访问Lua全局函数

int luaL_dofile (lua_State *L, const char *filename);
// 加载并运行文件 是个宏定义
// luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET,0) 

int luaL_loadfile (lua_State *L, const char *filename);
// 调用 load 函数,加载文件并编译文件为 lua 的 chunk,然后将其推到栈顶。

int lua_load(lua_State *L,
             lua_Reader reader,
             void *data,
             const char *chunkname,
             const char *mode);
// 加载一段 Lua 代码块,但不运行它。 如果没有错误, lua_load 把一个编译好的代码
// 块作为一个 Lua 函数压到栈顶。 否则,压入错误消息。

int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);
// 安全模式下的,lua_call。通常,最后一个参数填零
// if msgh == 0 then the error object returned on the stack is exactly the original error object

void lua_call (lua_State *L, int nargs, int nresults);
// 要想调用一个 lua 函数,流程如下,
// 第一,函数必须被压栈
// 第二,依次序压入参数,调用 lua_call,nargs 是入栈参数的个数。
// 第三,函数调用后,函数及其参数要出栈,
// 第四,返回值入栈,入栈顺序,先入栈者底,后入栈者顶,nresults 填入返回值的个数。

测试:

test.lua

function myfunc( name, a, b)
    return "my name is "..name  , a+b
end

c

extern "C"{
#include  <lua.h>
#include  <lualib.h>
#include <lauxlib.h>
}

void stackDump(lua_State *L) {
    int count = 0;
    printf("begin dump lua stack %d\n", count);
    
    int top = lua_gettop(L);
    for (int i=1; i <= top; ++i) {
        int t = lua_type(L, i);
        switch (t)
        {
        case LUA_TSTRING:
            printf("'%s'\n", lua_tostring(L, i));
            break;
        case LUA_TBOOLEAN:
            printf(lua_toboolean(L, i) ? "true\n" : "false\n");
            break;
        case LUA_TNUMBER:
            printf("%g\n", lua_tonumber(L, i));
            break;
        default:
            printf("%s\n", lua_typename(L, t));
            break;
        }
    }
}

int main(int argc, char **argv) {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    int ret = luaL_dofile(L, "test4.lua");
    printf("ret = %d\n", ret);

    lua_getglobal(L, "myfunc");
    lua_pushstring(L, "kirito");
    lua_pushinteger(L, 1);
    lua_pushnumber(L, 3.14);
    stackDump(L);

    lua_pcall(L, 3, 2, 0);
    const char * name = lua_tostring(L, -2);
    double a = lua_tonumber(L, -1);
    stackDump(L);
    printf("return %s, %lf\n", name, a);
    

    lua_close(L);
    return 0;
}

/*
ret = 0
begin dump lua stack 0
function
'kirito'
1
3.14
begin dump lua stack 0
'my name is kirito'
4.14
return my name is kirito, 4.140000
*/

C扩展Lua

​ Lua可以调用C的函数,必须先注册注册函数,即以一种恰当的方式为Lua提供C函数的地址。

​ Lua调用C函数时,也使用了一个与C调用Lua函数时相同类型的栈,C函数从栈中获取参数,并将结果压入栈。注意此处栈不是一个全局的栈,每个函数都用私有局部栈,Lua调用C时,第一个参数总是位于局部栈索引1的位置,栈底

​ 无论何时 Lua 调用 C, 被调用的函数都得到一个 新的栈,这个栈于 独立于 C 函数本身
的栈,也独立于之前的 Lua 栈。它里面包含了 Lua 传递给 C 函数的所有参数,而 C 函
数则把要返回的结果放入这个栈以返回给调用者。

Lua访问C入栈的值

api

void lua_setglobal (lua_State *L, const char *name);
// 将虚拟栈中,将栈顶元素弹出,作为全局 lua 变量 name 的值。

void lua_newtable (lua_State *L);
// 产生一个空表, 并推入栈

void lua_settable (lua_State *L, int index);
// 作一个等价于 t[k] = v 的操作,这里 t 是一个给定有效索引 index 处的值,v 指栈顶的值,而 k 是栈顶之下的那个值。
// 把栈顶作为 value,栈顶的下一个作为 key 设置到 index 指向的 table,最后把这两个全部弹出栈,这时候 settable 完成。
// lua_pushstring(L, "name");
// lua_pushstring(L, "123");
// lua_settable(L, -3);

void lua_setfield (lua_State *L, int index, const char *k);
// 等价于 t[k] = v,t 是栈上索引为 index 的表,v 是栈顶的值。函数结束,栈顶值v 会被弹出。
// lua_pushstring(L, "name");
// lua_pushstring(L, "123");
// lua_settable(L, -3);
// 等价于
// lua_pushstring(L,"123"); //此两句,可顶上三句
// lua_setfield(L, -2, "name");

测试:

test.lua

print("in lua ...")
print(name)
print(price)

print(t.name)
print(t.price)

c

extern "C"{
#include  <lua.h>
#include  <lualib.h>
#include <lauxlib.h>
}

void stackDump(lua_State *L) {
    int count = 0;
    printf("begin dump lua stack %d\n", count);
    
    int top = lua_gettop(L);
    for (int i=1; i <= top; ++i) {
        int t = lua_type(L, i);
        switch (t)
        {
        case LUA_TSTRING:
            printf("'%s'\n", lua_tostring(L, i));
            break;
        case LUA_TBOOLEAN:
            printf(lua_toboolean(L, i) ? "true\n" : "false\n");
            break;
        case LUA_TNUMBER:
            printf("%g\n", lua_tonumber(L, i));
            break;
        default:
            printf("%s\n", lua_typename(L, t));
            break;
        }
    }
}

int main(int argc, char **argv) {
    
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
   
    int price = 9999;
    const char *name = "kirito";

    lua_pushnumber(L, price);
    lua_setglobal(L, "price");
    stackDump(L);

    lua_pushstring(L, name);
    lua_setglobal(L, "name");
    stackDump(L);

    lua_newtable(L);
    lua_pushstring(L, "price");
    lua_pushinteger(L, 100);
    lua_settable(L, -3);

    lua_pushstring(L,"kirito"); //此两句,可顶上三句
    lua_setfield(L, -2, "name");
    lua_setglobal(L, "t");
    stackDump(L);

     int ret = luaL_dofile(L, "test5.lua");
    printf("ret = %d\n", ret);
    lua_close(L);
    return 0;
}
/*
begin dump lua stack 0
begin dump lua stack 0
begin dump lua stack 0
in lua ...
kirito
9999.0
kirito
100
ret = 0
*/

Lua调用C函数

api

typedef int (*lua_CFunction) (lua_State *L);
void lua_pushcfunction (lua_State *L, n lua_CFunction f);
// 将函数压入栈,该函数接受一个 C 类型的函数指针,并将其以 lua function 形式入栈。
// 在 lua 中调用该函数即会发生 c 函数的调用。
int foo(lua_State *L)
{
    int n = lua_gettop(L); // 栈顶idx,就是参数个数
    int sum = 0;
    for (int i=1; i<=n; ++i) {
        if (!lua_isnumber(L,i)) {
            lua_pushliteral(L, "incorrect argument");
			lua_error(L); // 返回
		}
        sum +=  lua_tonumber(L,i);
    }
    lua_pushnumber(L, sum/n);
    lua_pushnumber(L, sum); 
    return 2; // 返回值个数
}

void lua_register (lua_State *L, const char *name, lua_CFunction f);
// 其本质等同于先 pushcfunction,然后再 setglobal。

测试:

test.lua

a, b = foo(1,2,3,4);
print(a)
print(b)

c

extern "C"{
#include  <lua.h>
#include  <lualib.h>
#include <lauxlib.h>
}

void stackDump(lua_State *L) {
    int count = 0;
    printf("begin dump lua stack %d\n", count);
    
    int top = lua_gettop(L);
    for (int i=1; i <= top; ++i) {
        int t = lua_type(L, i);
        switch (t)
        {
        case LUA_TSTRING:
            printf("'%s'\n", lua_tostring(L, i));
            break;
        case LUA_TBOOLEAN:
            printf(lua_toboolean(L, i) ? "true\n" : "false\n");
            break;
        case LUA_TNUMBER:
            printf("%g\n", lua_tonumber(L, i));
            break;
        default:
            printf("%s\n", lua_typename(L, t));
            break;
        }
    }
}

int func_return_table(lua_State *L)
{
    lua_newtable(L); //创建一个表格, 放在栈顶
    lua_pushstring(L, "key"); //压入 key
    lua_pushnumber(L, 66); //压入 value
    lua_settable(L, -3); //弹出 key, value, 并设置到 table 里面去
    lua_pushstring(L,"foo");
    lua_pushcfunction(L,foo);
    lua_settable(L, -3); //
    return 1;
}

int foo(lua_State *L)
{
    int n = lua_gettop(L); // 栈顶idx,就是参数个数
    int sum = 0;
    for (int i=1; i<=n; ++i) {
        if (!lua_isnumber(L,i)) {
            lua_pushliteral(L, "incorrect argument");
			lua_error(L);
		}
        sum +=  lua_tonumber(L,i);
    }
    lua_pushnumber(L, sum/n);
    lua_pushnumber(L, sum); 
    return 2; // 返回值个数
}

int main(int argc, char **argv) {
    
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    
    lua_register(L, "foo", foo);
    
    int ret = luaL_dofile(L, "test6.lua");
    printf("ret = %d\n", ret);
    lua_close(L);
    return 0;
}
/*
2.0
10.0
ret = 0
*/

c函数批量注册

api

typedef struct luaL_Reg
{
	const char *name;
	lua_CFunction func;
} luaL_Reg;
// 用于存放,函数指针和注册的函数名。常用于生成数组,数组的最后一个元素,一定是以{NULL,NULL}结尾
// 等价于 luaL_newlibtable(L,l),luaL_setfuncs(L,l,0)

void luaL_newlib (lua_State *L, const luaL_Reg l[]);
// luaL_newlib 也是一个宏函数,简化了创建表和循环注册函数

void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);
// 创建一张新的表,并预分配足够保存下数组 l 内容的空间(但不填充)
void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
// 设置数组 l 中所有函数的到栈顶的表中 第三个参数通常为 0

void luaL_requiref (lua_State *L,
                    const char *modname,
                    lua_CFunction  openf,
                    int glb);
// 如果 modname 不在 package.loaded 中,则调用 openf 函数以 modname 为参数,使其为 package.loaded[modname]。其行为类似于 require,如果 glb 为 true,则存储模块到全局的 modname。

测试:

test.lua

print(my.add(1,2))
print(my.foo(1,2))

c

extern "C"{
#include  <lua.h>
#include  <lualib.h>
#include <lauxlib.h>
}

void stackDump(lua_State *L) {
    int count = 0;
    printf("begin dump lua stack %d\n", count);
    
    int top = lua_gettop(L);
    for (int i=1; i <= top; ++i) {
        int t = lua_type(L, i);
        switch (t)
        {
        case LUA_TSTRING:
            printf("'%s'\n", lua_tostring(L, i));
            break;
        case LUA_TBOOLEAN:
            printf(lua_toboolean(L, i) ? "true\n" : "false\n");
            break;
        case LUA_TNUMBER:
            printf("%g\n", lua_tonumber(L, i));
            break;
        default:
            printf("%s\n", lua_typename(L, t));
            break;
        }
    }
}

int foo(lua_State *L)
{
    int n = lua_gettop(L); // 栈顶idx,就是参数个数
    int sum = 0;
    for (int i=1; i<=n; ++i) {
        if (!lua_isnumber(L,i)) {
            lua_pushliteral(L, "incorrect argument");
			lua_error(L);
		}
        sum +=  lua_tonumber(L,i);
    }
    lua_pushnumber(L, sum/n);
    lua_pushnumber(L, sum); 
    return 2; // 返回值个数
}

int add(lua_State *L)
{
    int n = lua_gettop(L);
    int sum = 0;
    for (int i=0; i<n; ++i) {
        sum+=lua_tonumber(L, i+1);
    }
    if (n!=0) {
        lua_pushnumber(L, sum);
        return 1;
    }
    return 0;
}

const luaL_Reg lib[] = 
{
    {"foo", foo},
    {"add", add},
    {NULL,NULL}
};

int luaopen_my(lua_State *L) {
    luaL_newlib(L, lib);
    return 1;
}

int main(int argc, char **argv) {
    
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    // 统一注册lua中调用的函数
    luaL_requiref(L, "my", luaopen_my, 1);
    stackDump(L);
    
     int ret = luaL_dofile(L, "test7.lua");
    printf("ret = %d\n", ret);
    lua_close(L);
    
    return 0;
}
/*
begin dump lua stack 0
table
3.0
1.0     3.0
ret = 0
*/

c++生成dll/so

c

extern "C"{
#include  <lua.h>
#include  <lualib.h>
#include <lauxlib.h>
}

int foo(lua_State *L)
{
    int n = lua_gettop(L); // 栈顶idx,就是参数个数
    int sum = 0;
    for (int i=1; i<=n; ++i) {
        if (!lua_isnumber(L,i)) {
            lua_pushliteral(L, "incorrect argument");
			lua_error(L);
		}
        sum +=  lua_tonumber(L,i);
    }
    lua_pushnumber(L, sum/n);
    lua_pushnumber(L, sum); 
    return 2; // 返回值个数
}

int add(lua_State *L)
{
    int n = lua_gettop(L);
    int sum = 0;
    for (int i=0; i<n; ++i) {
        sum+=lua_tonumber(L, i+1);
    }
    if (n!=0) {
        lua_pushnumber(L, sum);
        return 1;
    }
    return 0;
}

const luaL_Reg lib[] = 
{
    {"foo", foo},
    {"add", add},
    {NULL,NULL}
};

extern "C"{
//  luaopen_xx  xx必须和最后生成库的名字一致 比如 my.so luaopen_my
int luaopen_my(lua_State *L) {
    luaL_newlib(L, lib);
    return 1;
}
}

lua

-- 动态库名字改成my.so
my=require("my")

print(my.add(1,2))
print(my.foo(1,2))

Lua

环境安装

$ curl -LO http://www.lua.org/ftp/lua-5.3.5.tar.gz
$ tar -xzf lua-5.3.5.tar.gz
$ cd lua-5.3.5/
# 依赖 libreadline-dev
$ make linux test
$ sudo make install
$ lua -v # 检查

for win

简介

数据类型

类型 描述
nil 无效值
boolean false与true
number 相当于double
string 'str'或者"str"
function C或Lua函数
userdata 存储在变量中的C数据结构
thread 协程
table 关联数组

语法

-- 注释
--[[
多行注释
]]
print("Hello World")
--[[关键词
and break do else
elseif end false for
function if in local
nil not or repeat return
then true until while goto
一般约定,以下划线开头连接一串大写字母的名字(比如 _VERSION)被保留用于 Lua 内部全局变量。
]]
print(type("Hello world"))      --> string
print(type(10.4*3))             --> number
print(type(print))              --> function
print(type(type))               --> function
print(type(true))               --> boolean
print(type(nil))                --> nil
print(type(type(X)))            --> string
-- 给全局变量或者 table 表里的变量赋一个 nil 值,等同于把它们删掉
tab1 = { key1 = "val1", key2 = "val2", "val3" }
for k, v in pairs(tab1) do
    print(k .. " - " .. v)
end
type(X)=="nil" -- 作比较应该加双引号
--  false 和 nil 看作是 false,其他的都为 true,数字 0 也是 true
if false or nil then
    print("至少有一个是 true")
else
    print("false 和 nil 都为 false")
end
-- 可以用方括号表示一块字符串
str = [[
123
124
]]

-- 在对一个数字字符串上进行算术操作时,Lua 会尝试将这个数字字符串转成一个数字
-- 字符串连接使用的是 .. 
print("str" .. 1) -- str1
print(123 .. 123) -- 123123 数值连接
-- 使用 # 来计算字符串的长度
str = "123"
print(#str)
print(#"123")

-- local 局部变量 省略为全局变量
local tab = {}
local tbl2 = {"apple", "pear", "orange", "grape"} -- 默认初始索引一般以1开始

function factorial1(n)
    if n == 0 then
        return 1
    else
        return n * factorial1(n - 1)
    end
end
factorial2 = factorial1

-- 赋值
x = 1
x, y = y, x   
a, b = f() -- f可以多参返回,返回少了就是nil

-- 对于table
t[i]
t.i                 -- 当索引为字符串类型时的一种简化写法
gettable_event(t,i) -- 采用索引访问本质上是一个类似这样的函数调用

循环

while( a < 20 )
do
   print("a 的值为:", a)
   a = a+1
end

-- var 从 exp1 变化到 exp2,每次变化以 exp3 为步长递增 var,并执行一次 "执行体"。exp3 是可选的,如果不指定,默认为1。
for var=exp1,exp2,exp3 do  
    <执行体>  
end 

for i=1,f(x) do
    print(i)
end
 
for i=10,1,-1 do
    print(i)
end

a = {"one", "two", "three"}
for i, v in ipairs(a) do
    print(i, v)
end 

repeat
   print("a的值为:", a)
   a = a + 1
until( a > 15 )

流程控制

--[ 0 为 true ]
if(0)
then
    print("0 为 true")
end

if( a == 10 )
then
   print("a 的值为 10" )
elseif( a == 20 )
then  
   print("a 的值为 20" )
elseif( a == 30 )
then
   print("a 的值为 30" )
else
   print("没有匹配 a 的值" )
end
print("a 的真实值为: ", a )

函数

local function max(num1, num2)

   if (num1 > num2) then
      result = num1;
   else
      result = num2;
   end

   return result;
end

function maximum (a)
    local mi = 1             -- 最大值索引
    local m = a[mi]          -- 最大值
    for i,val in ipairs(a) do
       if val > m then
           mi = i
           m = val
       end
    end
    return m, mi
end

print(maximum({8,10,23,12,5}))

-- 可变参
function add(...)  
    -- select("#",...) 来获取可变参数的数量
    print("总共传入 " .. select("#",...) .. " 个数")
    local s = 0  
    for i, v in ipairs{...} do   --> {...} 表示一个由所有变长参数构成的数组  
        s = s + v  
    end  
    return s  
end  
print(add(3,4,5,6,7))  --->25

function fwrite(fmt, ...)  ---> 固定的参数fmt
    return io.write(string.format(fmt, ...))    
end

function foo(...)  
    for i = 1, select('#', ...) do  -->获取参数总数
        local arg = select(i, ...); -->读取参数
        print("arg", arg);  
    end  
end  
foo(1, 2, 3, 4); 

运算符

+ - * / % ^(乘幂)
== ~= > < >= <=
and or not
..(连接符 两个点!)
#(一元运算符,返回字符串或表的长度)

数组

-- 初始化多维数组
array = {}
for i=1,3 do
   array[i] = {}
      for j=1,3 do
         array[i][j] = i*j
      end
end

-- 访问数组
for i=1,3 do
   for j=1,3 do
      print(array[i][j])
   end
end

迭代器

-- 泛型 for 迭代器
-- 泛型 for 在自己内部保存迭代函数,实际上它保存三个值:迭代函数、状态常量、控制变量。
for k, v in pairs(t) do
    print(k, v)
end
-- 使用了 Lua 默认提供的迭代函数 ipairs
array = {"Google", "Runoob"}
for key,value in ipairs(array)
do
   print(key, value)
end

-- 无状态的迭代器
function square(iteratorMaxCount,currentNumber)
   if currentNumber<iteratorMaxCount
   then
      currentNumber = currentNumber+1
   return currentNumber, currentNumber*currentNumber
   end
end

-- 泛型 for 需要三个值:迭代函数、状态常量、控制变量
-- 对于 for 结构来说,状态常量没有用处,仅初始化用
for i,n in square,3,0
do
   print(i,n)
end

function iter (a, i)
    i = i + 1
    local v = a[i]
    if v then
       return i, v
    end
end
 
function ipairs (a)
    return iter, a, 0
end

-- 多状态的迭代器
array = {"Google", "Runoob"}
function elementIterator (collection)
   local index = 0
   local count = #collection
   -- 闭包函数
   return function ()
      index = index + 1
      if index <= count
      then
         --  返回迭代器的当前元素
         return collection[index]
      end
   end
end

for element in elementIterator(array)
do
   print(element)
end

模块与包

-- 文件名为 module.lua
-- 定义一个名为 module 的模块
module = {}
 
-- 定义一个常量
module.constant = "这是一个常量"
 
-- 定义一个函数
function module.func1()
    io.write("这是一个公有函数!\n")
end
 
local function func2()
    print("这是一个私有函数!")
end
 
function module.func3()
    func2()
end
 
return module

--------------------------------------使用包
-- test_module.lua 文件
-- module 模块为上文提到到 module.lua
module = require("module")
 
print(module.constant)
 
module.func3()

--[[
  对于自定义的模块,模块文件不是放在哪个文件目录都行,函数 require 有它自己的文件路径加载策略,它会尝试从 Lua 文件或 C 程序库中加载模块。
  require 用于搜索 Lua 文件的路径是存放在全局变量 package.path 中,当 Lua 启动后,会以环境变量 LUA_PATH 的值来初始这个环境变量。如果没有找到该环境变量,则使用一个编译时定义的默认路径来初始化。
#LUA_PATH
export LUA_PATH="~/lua/?.lua;;"
文件路径以 ";" 号分隔,最后的 2 个 ";;" 表示新加的路径后面加上原来的默认路径。 
]]

-----c 包
local path = "/usr/local/lua/lib/libluasocket.so"
local f = loadlib(path, "luaopen_socket")

local path = "/usr/local/lua/lib/libluasocket.so"
-- 或者 path = "C:\\windows\\luasocket.dll",这是 Window 平台下
local f = assert(loadlib(path, "luaopen_socket"))
f()  -- 真正打开库

协程

方法 描述
coroutine.create() 创建 coroutine,返回 coroutine, 参数是一个函数,当和 resume 配合使用的时候就唤醒函数调用
coroutine.resume() 重启 coroutine,和 create 配合使用
coroutine.yield() 挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果
coroutine.status() 查看 coroutine 的状态 注:coroutine 的状态有三种:dead,suspended,running,具体什么时候有这样的状态请参考下面的程序
coroutine.wrap() 创建 coroutine,返回一个函数,一旦你调用这个函数,就进入 coroutine,和 create 功能重复
coroutine.running() 返回正在跑的 coroutine,一个 coroutine 就是一个线程,当使用running的时候,就是返回一个 corouting 的线程号
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!