C/C++與lua的交互

C/C++與lua之間能過實現交互,它的原理是:
1.lua裏面的API都是用C寫的。
2.lua跟C/C++的交互是通過一個虛擬stack來進行數據的溝通的。在VS工程中,我們需要加入C API的頭文件lua.h, luaconfig.h , lualib.h, luaxlib.h 。這幾個頭文件都是lua源代碼,可以直接下載使用。lua.h提供原子級別的API,對棧的基本操作都在裏面實現,裏面的API都是lua_開頭。luaxlib.h 定義了輔助庫提供的函數,它的所有定義都以luaL_開頭,輔助庫是一個使用lua.h中的API編寫出的一個較高的抽象層。下面看下完整源代碼:

#include "stdafx.h"  
#include "stdio.h"  
extern "C"  
{  
    #include "lua.h"   //提供原子級別的API
    #include "lualib.h"  
    #include "lauxlib.h"  //定義了輔助哭提供的函數
};  //lua頭文件中的API都是用C寫的  

#pragma comment(lib,"lua5.1.lib")       //讓程序知道調用的lua裏面的API可以直接在這個庫裏面找  

//這個函數,我們實現將壓進stack裏面的所有數據,從base到top,根據不同類型打印出來  
void stackDump(lua_State *L)  
{  
    int i;  
    int top = lua_gettop(L);  //獲取stack大小  
    for ( i = 1;i <= top;i++ )  
    {  
        int type = lua_type(L, i);  
        switch(type)  
        {  
        case LUA_TSTRING:  
            {  
                printf("%s",lua_tostring(L, i));  //lua庫中的函數,添加了頭文件,可以直接使用
                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));  
                break;  
            }  
        }  
        printf(" ");  
    }  
    printf("\n");  
}  


int _tmain(int argc, _TCHAR* argv[])  
{  
    lua_State *L;    //創建一個lua_State實例
    L = luaL_newstate();    //必須要創建lua_State環境,stack存在於這個環境中  
    luaL_openlibs(L);   //加載lua靜態鏈接庫lua5.1.lib  
    lua_pushboolean(L,true);  
    lua_pushinteger(L,2);  
    lua_pushnumber(L,2.333);  
    lua_pushstring(L,"then");   //分別壓入了四個不同類型的元素,現在stack裏面,從base到top依次爲 true , 2 , 2.333 ,then  
    stackDump(L);           //打印結果 從base到top爲 true , 2 , 2.333 ,then  
    printf("stay here");  
    return 0;  
}  

C API. Lua既是一種擴展語言,也是一種可擴展語言;說它是擴展語言,意思是C/C++可以用lua進行擴展,這時C/C++擁有控制權,lua是一個庫,這種形式的C/C++代碼稱爲“應用程序代碼”;說它是可擴展語言,意思是lua自身也可以通過在lua環境中註冊用C語言(或其他語言)實現的函數,然後lua可以直接調用這些函數,這時lua擁有控制權,C是一個庫,這種形式的C代碼稱爲“庫代碼”。這就是C跟lua交互的兩種形式。應用程序代碼與庫代碼都使用相同的API來與lua通信,這些API就是C API

C API

Lua腳本實現交互提供了一系列的C API,常用API有:

luaL_newstate函數用於初始化一個lua_State實例
luaL_openlibs函數用於打開Lua中的所有標準庫,如io庫、string庫等。
luaL_loadbuffer編譯了buff中的Lua代碼,如果沒有錯誤,則返回0,同時將編譯後的程序塊壓入虛擬棧中。
lua_pcall函數會將程序塊從棧中彈出,並在保護模式下運行該程序塊。執行成功返回0,否則將錯誤信息壓入棧中。
lua_tostring函數中的-1,表示棧頂的索引值,棧底的索引值爲1,以此類推。該函數將返回棧頂的錯誤信息,但是不會將其從棧中彈出。
lua_pop是一個宏,用於從虛擬棧中彈出指定數量的元素,這裏的1表示僅彈出棧頂的元素。
lua_close用於釋放狀態指針所引用的資源
Lua針對每種C類型,都有一個C API函數與之對應,如:
void lua_pushnil(lua_State* L);  --nil值
void lua_pushboolean(lua_State* L, int b); --布爾值
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 len); --指定長度的內存數據
void lua_pushstring(lua_State* L, const char* s);  --以零結尾的字符串,其長度可由strlen得出
Lua提供了一組特定的函數用於檢查返回元素的類型,如:
int lua_isboolean (lua_State *L, int index);
int lua_iscfunction (lua_State *L, int index);
int lua_isfunction (lua_State *L, int index);
int lua_isnil (lua_State *L, int index);
int lua_islightuserdata (lua_State *L, int index);
int lua_isnumber (lua_State *L, int index);
int lua_isstring (lua_State *L, int index);
int lua_istable (lua_State *L, int index);
int lua_isuserdata (lua_State *L, int index);
 以上函數,成功返回1,否則返回0。需要特別指出的是,對於lua_isnumber而言,不會檢查值是否爲數字類型,而是檢查值是否能轉換爲數字類型

C/C++與lua交互的總結:
1.引入lua的庫函數

extern "C"  
{  
    #include "lua.h"   //提供原子級別的API
    #include "lualib.h"  
    #include "lauxlib.h"  //定義了輔助哭提供的函數
};//C++代碼中,用extern "C" 區別c代碼,因爲lua頭文件中的API都是用C寫的

2.創建一個lua_State對象

lua_State *L;    //創建一個lua_State實例,lua_State主要是管理一個lua虛擬機的執行環境, 一個lua虛擬機可以有多個執行環境。Lua虛擬機通過維護這樣一個虛擬棧來實現兩種之間的通信

//C/C++與lua的數據通信
//Lua虛擬機提供Lua_State這樣一種數據結構。任何一種數據從C\C++傳入Lua虛擬機中,Lua都會將這類數據轉換爲一種通用的結構lua_TValue,並且將數據複製一份,將其壓入虛擬棧中

3.初始化實例

L = luaL_newstate();    //必須要創建lua_State環境,stack存在於這個環境中

4.打開Lua中的所有標準庫

  luaL_openlibs(L);   //加載lua靜態鏈接庫lua5.1.lib 

5.向stack中添加數據

    lua_pushboolean(L,true);  
    lua_pushinteger(L,2);  
    lua_pushnumber(L,2.333);  
    lua_pushstring(L,"then"); //類似於棧,第一個數據放在棧底,API使用“索引”來引用棧中的元素,第一個壓入棧的爲1,第二個爲2,依此類推。我們也可以使用負數作爲索引值,其中-1表示爲棧頂元素,-2爲棧頂下面的元素,同樣依此類推

6.將stack中的數據讀出來

 stackDump(L)
發佈了46 篇原創文章 · 獲贊 13 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章