lua學習筆記3-c調用lua

lua C api

PS:這里是默認我已經學完了lua腳本的基本知識(包括table,元表,函數,基本庫, 文件io,庫導入等等)

lua是c寫的,無論是lua調用c還是c調用lua都非常容易,以下是基于文檔做的一些學習筆記,在文檔的索引可以快速找到api的名稱方便參考,文檔地址如下:
官網5.3文檔:http://www.lua.org/manual/5.3/#index
中文文檔:http://www.runoob.com/manual/lua53doc/contents.html#index

文檔包括兩部分,一部分是介紹lua的語法,以及一些注(keng)意(die)事項,比如其中說到空字符串和0都被認為是true,恩,要注意(MDZZ),感覺lua的強大之處在于他的table(手動咸魚),下面開始修仙,下面通過問答的方式給自己學習lua做一些筆記,在此之前,先編譯lua,我們到官網可以下載lua的源碼

源碼下載頁面:http://www.lua.org/download.html
5.3源碼下載:http://www.lua.org/ftp/lua-5.3.4.tar.gz

lua源碼非常小,很容易編譯,windows下,裝個Mingw即可用make編譯,以下是linux的

1.下載解壓源碼

wget http://www.lua.org/ftp/lua-5.3.4.tar.gz
tar -xzvf lua-5.3.4.tar.gz
~/local/lua/lua-5.3.4$ make
Please do 'make PLATFORM' where PLATFORM is one of these:
   aix bsd c89 freebsd generic linux macosx mingw posix solaris
See doc/readme.html for complete instructions.

上面提示指定編譯選項,如果是windows下用Mingw的,就make -j12 mingw, -j12是多線程編譯,分12個線程編譯,現在是debian,可以選擇posix,如果提示缺少一些庫,使用apt-get 安裝即可

make -j12 posix

編譯成功后,在src文件生成一個lua(lua解釋器),luac(lua腳本編譯器),以及靜態庫liblua.a,c調用lua的時候,現在是用靜態庫,現在把以下文件復制到項目目錄下
頭文件:lua.h lualib.h lauxlib.h luaconf.h
靜態庫文件:liblua.a
我的項目目錄為:~/project/lua
我把頭文件放置在~/project/lua/include
靜態庫文件放在~/project/lua/lib

以下所有的操作都是在項目目錄(用$PRO_HOME描述這個目錄)


1.c是如何調用lua寫的代碼的?

1.首先了解,lua在c代碼中是如何“工作”的,在c中要調用lua,首先我得創建一個lua狀態機(lua_State)
文件$PRO_HOME/main.c

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

int main(void)
{
  //創建一個lua狀態機
  lua_State *L  = luaL_newstate();
  //銷毀這貨
  lua_close(L);
  return 0;
}

然后嘗試編譯這個源文件

$gcc -I ../include -c main.c
$gcc -lm -o main main.o ../lib/liblua.a

編譯成功說明配置沒有問題

c調用lua代碼,首先要學會怎么把lua代碼“翻譯”成c的代碼,先不著急如何把lua代碼加載到lua狀態機運行,先了解下它是怎么運行的,根據文檔參考,寫以下一段代碼

-- a是一個全局變量
a="測試"
print(a)

a是一個全局變量,在lua中,無非在維護一個堆棧stack和一個環境表_G(暫時理解)
那么用c怎么寫呢?
1.創建一個狀態機(lua_State),加載基本庫(luaL_openlibs())
2.把字符串“測試”壓入堆棧(lua_pushstring)
3.把這個字符串彈出,設置為global,名稱為a(lua_setglobal())
4.從全局變量中,把print函數壓棧(lua_getglobal())
5.把參數a從全局變量中壓棧(lua_getglobal())
6.調用lua_call執行函數

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

int main(void)
{
    lua_State *L = luaL_newstate();
   //加載基本庫(print在其中)
    luaL_openlibs(L);
    //這里相當于設置全局變量a="測試"
    lua_pushstring(L,"測試");
    lua_setglobal(L,"a");
    //print函數壓棧
    lua_getglobal(L,"print");
    //參數壓棧yiban
    lua_getglobal(L,"a");
    //調用函數,1個參數,0個返回值
    lua_call(L,1,0);
    lua_close(L);
    return 0;
}

小總結:

在lua 的 C api中,
數據類型有:
lua_Integer 整形
lua_Number 默認對應的是C double
lua_Unsigned 無符號整形

字符串、布爾型或者是lua的table之類的,都是不能直接“拿出來”的
如果要操作,設置某某某的變量,可以通過lua_pushxxxx來把對應的數據類型的變量的值壓入堆棧,如果,要把變量設置為一個全局變量,就把它設置為global(lua_setglobal()),lua_setglobal會把棧頂的元素彈出,病設置到環境表,詳情查看文檔,

關于堆棧

lua的堆棧是lua自己實現的一個數據結構,并不是c語言執行時的那個堆棧,這個堆棧,由棧底往棧頂數,元素的序號是1 2 3 4 5...,這是它的絕對索引的方式,還有它支持負索引,也就是參考點是棧頂,而不是棧底,比如-1代表的是棧頂的元素,-2代表棧頂的下一個元素

對于堆棧的操作有:
1.獲取棧頂的索引值,lua_gettop(L)(這個值,可以當做是棧元素個數)

2.把數據壓棧(lua_pushxxx,根據壓入的數據類型不一樣,有對應有一系列的操作函數,例如,lua_pushstring(L,"測試"),把字符串壓入,詳情看文檔lua_pushxxxx),又或者是

3.把堆棧的元素“讀取”出來,lua_toxxxx,就可以不彈出堆棧中的數據,把它轉換成c的數據類型,例如:lua_tolstring,注意,這個返回值是const類型,也就是說你不能對他進行更改,如果要做其他用途,你需要
把他copy出來

4.更改元素在堆棧中的位置

5.lua有垃圾回收機制GC,一般不用擔心內存釋放的問題


2.如何在lua狀態機中執行一個c寫的函數?

剛剛已經學了,如何在c中,“執行”lua,這個print函數他已經實現了,但是我們自己怎么實現一個函數,然后在lua中調用呢?
這個函數可以是
1.lua寫的函數
2.c寫的可以讓lua識別的函數
我們先來搞第二種,程序還是在原來的基礎上進行擴充

我們把print換成我們自己實現的一個函數,這個函數在lua里叫print2,它比較簡單,只能接受一個參數,不做任何檢查,也不做任何的錯誤的處理

lua注冊的函數的類型是:
static int fun(lua_State *L);
返回值是這個函數的返回值個數(因為lua支持多個返回值,執行完畢后,把返回值依次壓棧,然后返回返回值個數就行了),調用結束后,堆棧中剩下的是fun的返回值(如果有返回值,并且按照順序壓棧)

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

static int print2(lua_State *L)
{
   const char * s = luaL_optlstring (L,1,"啥都沒",NULL);  //獲取函數調用時第1個參數為字符串,如果參數不存在或者是nil就返回“啥都沒”,并且把長度放在第四個參數(這里設置為NULL,不獲取長度),
  printf("這是:%s\n",s);
  return 0;  //返回值個數為0
}

int main(void)
{
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);      //加載基本庫(print在其中)
    //這里相當于設置全局變量a=image.png"測試"
    lua_pushstring(L,"測試");
    lua_setglobal(L,"a");
  
  //注冊這個函數到全局表 
    lua_register(L,"print2",print2);

    lua_getglobal(L,"print2");      //把這個函數從全局表中壓棧
    lua_getglobal(L,"a");         //參數壓棧
    lua_call(L,1,0);         //調用函數,1個參數,0個返回值
    lua_close(L);          //關閉狀態機
    return 0;
}

未完待續

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 原文地址:C語言函數調用棧(一)C語言函數調用棧(二) 0 引言 程序的執行過程可看作連續的函數調用。當一個函數執...
    小豬啊嗚閱讀 4,674評論 1 19
  • 當在Lua和C之間交換數據時主要的問題是自動回收與手動回收內存管理的不一致。因此,Lua 用一個抽象的棧在Lua與...
    luffier閱讀 2,695評論 0 3
  • 第一篇 語言 第0章 序言 Lua僅讓你用少量的代碼解決關鍵問題。 Lua所提供的機制是C不擅長的:高級語言,動態...
    testfor閱讀 2,719評論 1 7
  • 1. 寫在前面 很多時候我們都需要借助一些腳本語言來為我們實現一些動態的配置,那么就會涉及到如何讓腳本語言跟原生語...
    杰嗒嗒的阿杰閱讀 3,454評論 9 31
  • 昨天和孩子爸討論了孩子教育的問題。 這次是有效的一次溝通。 孩子的爸爸比我,有耐心,我把孩子學過的和要預習的數學和...
    里娃閱讀 127評論 0 0