天天看點

Lua和C互相調用

目錄

C虛拟棧技術

壓入元素

查詢元素

其他棧操作

lua_is*函數

lua_to*函數從棧中擷取一個值

練習

C調用Lua的函數、全局變量

Lua調用C的函數

Lua和C語言通信一個技術。幾乎所有的API調用都會操作這個棧上的值。           
void lua_pushnil(lua_State *L);
void lua_pushboolean(lua_State *L,int bool);
void lua_pushnumber(lua_State *L, lua_Number n);
void lua_pushinteger(lua_State *L, lua_Integer);
void lua_pushlstring(lua_State *L, const char *s, size_t len);
void lua_pushstring(lua_State *L, const char *s);
判斷虛拟棧内是否有足夠的空間
int lua_checkstack(lua_State *L, int sz);           
API使用索引來引用棧中的元素。第一個壓入棧中的元素索引為1(棧底),第二個壓入為2.用負數來通路棧中的元素,-1表示棧頂元素,-2表示棧頂下面的元素,以此類推           
int lua_gettop(lua_State *L);//傳回棧頂索引,相當于求棧長度
void lua_settop(lua_State *L, int index);//将棧頂指定某個位置
void lua_pushvalue(lua_State *L, int index);//指派index元素并壓入棧
void lua_remove(lua_State *L, int index);//将index的元素删除
void lua_insert(lua_State *L, int index);//将棧頂元素插入到index位置,index之後的位置往棧上方移動一位
void lua_replace(lua_State *L, int index);//将棧頂元素替換index的元素
void lua_pop(lua_State *L, int n);//删除n個棧頂元素            
為了檢查一個元素是否為特定的類型,API提供了lua_is*.lua_isnumber、lua_isstring、lua_istable等
int lua_is*(lua_State int index); --給定的索引值是,在L中的索引
​
實際上,lua_isnumber是檢查值是否能轉換為數字類型,lua_isstring也有同樣的行為           
int lua_toboolean(lua_State *L, int index);
lua_Number lua_tonumber(lua_State *L, int index);  --index為負數時,就是出棧?
lua_Integer lua_tointeger(lua_State *L, int index);
const char *lua_tolstring(lua_State *L, int index, size_t *len);
size_t lua_objlen(lua_State *L, int index);
​
lua_tolstring函數傳回的是指向内部字元串副本的指針,并且不能修改。當對應的字元還在Lua的棧内,那麼這個指針就會一直有效。當Lua調用一個C函數傳回時,Lua就會清空它的棧。這就形成了一條規則,不要在函數之外使用在C函數内獲得指向Lua字元串的指針
​
lua_lstring傳回的字元串在其末尾都會有一個額外的零。字元串長度會在函數第三個參數傳回。           

練習

功能:由下而上列印棧内元素

【main.cpp】

#include<stdio.h>
​
extern "C"
{
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
}
lua_State *L;
​
static void stackDump()
{
    int lens = lua_gettop(L);
    for(int i = 1; i <= lens; ++i){
        int type = lua_type(L, i);
        switch(type)
        {
            case LUA_TSTRING:{
                printf("%s", lua_tostring(L, i));
                break;
            }
            case LUA_TBOOLEAN:{
                printf(lua_toboolean(L, i) ? "True" : "False");
                break;
            }
            case LUA_TNUMBER:{
                printf("%g", lua_tonumber(L, i));
                break;
            }
            default:{
                printf("%s", lua_typename(L, i));
            }
        }
        printf("\n");
    }
}
​
void run()
{
    lua_getglobal(L, "width");
    lua_getglobal(L, "length");
    lua_getglobal(L, "height");
​
    stackDump();
}
​
int main()
{
    L = luaL_newstate();
    luaL_openlibs(L);
    luaL_dofile(L, "add.lua");
    run();
}           
【add.lua】           
width = 7
length = 8
height = 9
​
function add(x, y)
    -- print("x:",x,"y:",y)
    return x + y
end           

C調用Lua的函數、全局變量

步驟:

1、函數入棧,參數按正序入棧

2、void lua_call(lua_State,*L int nargs, int results)//nargs是參數的個數,results是傳回的數量   會從棧中取出元素

3、從棧頂取出函數進行運算,将結果壓入棧中

4、以上操作會把參數、函數本身出棧

通過lua_getglobal函數擷取Lua的函數名、全局變量

通過虛拟棧進行資料交換

#include<bits/stdc++.h>
using namespace std;
extern "C"
{
    #include "lua.hpp"
    #include "lualib.h"
    #include "lauxlib.h"
}

lua_State *L;

int add(int x, int y)
{
    lua_getglobal(L, "add");//調用函數的步驟,放入函數,參數按序放入,然後調用lua_call
    lua_pushnumber(L, x);
    lua_pushnumber(L, y);
    lua_call(L, 2, 1); //棧取出棧2個參數、1個傳回值入棧

    int sum = lua_tonumber(L, - 1);

    lua_getglobal(L, "width");
    lua_getglobal(L, "height");
    lua_getglobal(L, "length");

    int lens = lua_gettop(L);
    printf("lens: %d\n", lens);
    for(int i = 1; i <= lens; ++i){
        int num = lua_tonumber(L, i);
        printf("num:%d\n", num);
    }
    return sum;
}

int main()
{
    L = luaL_newstate();
    luaL_openlibs(L);
    luaL_dofile(L, "add.lua");
    int sum = add(10, 20);
    printf("%d\n", sum);
    lua_close(L);
    return 0;
}
           

【add.lua】

width = 1
height = 2
length = 3

function add(x, y)
	return x + y
end
           

Lua調用C的函數

其實還是在C工程下運作,隻不過注冊函數到Lua中,Lua調用了C函數

比較精妙的一點是,C注冊函數至Lua後,Lua調用這個函數時傳遞的參數個數是動态的,會全部放入隻屬于這個函數的虛拟棧内,C函數通過取出棧内元素進行操作。

操作後的答案繼續放入棧中,并且傳回一個整數,代表答案的個數,Lua内通過相同數量的全局變量即可獲得所有答案

注冊函數兩種方法

方法1: lua_register(L, "addmethod", Addmethod);

方法2:

lua_pushcfunction(L, Addmethod);

 lua_setglobal(L, "addmethod");

#include<bits/stdc++.h>
using namespace std;

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

lua_State *L;

static int Addmethod(lua_State *t)
{
    int first = luaL_checknumber(t, 1);
    int second = luaL_checknumber(t, 2);
    lua_pushnumber(t, first + second);
    return 1;
}

static int Printmethod(lua_State *t)
{
    int answer = luaL_checknumber(t, 1);
    printf("answer:%d\n", answer);
    return 0;
}


int main()
{
    L = luaL_newstate();
    luaL_openlibs(L);
    
    lua_register(L, "addmethod", Addmethod);
    lua_register(L, "printmethod", Printmethod);

    luaL_dofile(L, "add.lua");


    lua_close(L);
    return 0;
}
           
first = 10
second = 20
local ans = addmethod(10, 20)
printmethod(ans)