lua編程之lua與C相互調用

來源:互聯網
上載者:User

標籤:style   blog   http   io   color   os   ar   使用   sp   

lua是擴充性非常良好的語言,雖然核心非常精簡,但是使用者可以依靠lua庫來實現大部分工作。除此之外,lua還可以通過與C函數相互調用來擴充程式功能。在C中嵌入lua指令碼既可以讓使用者在不重新編譯代碼的情況下修改lua代碼更新程式,也可以給使用者提供一個自由定製的介面,這種方法遵循了機制與策略分離的原則。在lua中調用C函數可以提高程式的運行效率。lua與C的相互調用在工程中相當實用,本文就來講解lua與C相互調用的方法。

Lua與C相互調用的首要問題是如何交換資料,lua API使用了一個抽象的棧與C語言交換資料,提供了壓入元素,查詢元素和彈出元素等功能的API操作棧,這裡可以查看lua5.2中每個函數的詳細文檔,棧中的元素可以通過索引訪問,從棧底向上是從1開始遞增的正整數,從棧頂向下是從-1開始遞減的負整數,棧的元素按照FIFO的規則進出。

一、 C調用lua

先通過一個簡單的例子瞭解C是怎麼調用lua的,

//test.luawidth = 10height = 20//test.c#include <stdio.h>#include <lua.h>#include <lualib.h>#include <lauxlib.h>int main() {  lua_State *L = luaL_newstate();  luaL_openlibs(L);  if(luaL_loadfile(L, "test.lua") || lua_pcall(L, 0,0,0)){    printf("error %s\n", lua_tostring(L,-1));    return -1;  }  lua_getglobal(L,"width");  lua_getglobal(L,"length");  printf("width = %d\n", lua_tointeger(L,-2));  printf("length = %d\n", lua_tointeger(L,-1));  lua_close(L);  return 0;}

luaL_newstate建立一個新的lua_State,C和lua的所有操作都要依賴這個lua環境, luaL_openlibs將lualib.h中定義的lua標準庫載入到進lua_State。

luaL_loadfile從檔案中載入lua代碼並編譯,編譯成功後的程式塊被壓入棧中,

lua_pcall會將程式塊彈出並在保護模式下解釋執行。代碼中調用lua_pcall就在lua_State中定義了 width和 length兩個全域變數。

lua_getglobal將全域變數的值壓入棧中,width先入棧,在-2的位置,length在棧頂。

除了變數,C代碼還可以直接調用lua中定義的函數

//test.luafunction add(x, y)  return x+yend//test.c#include <stdio.h>#include <lua.h>#include <lualib.h>#include <lauxlib.h>#include <math.h>int main() {  lua_State *L = luaL_newstate();  luaL_openlibs(L);  if(luaL_loadfile(L, "test.lua") || lua_pcall(L, 0,0,0)){    printf("error %s\n", lua_tostring(L,-1));    return -1;  }  lua_getglobal(L,"add");  lua_pushnumber(L, 10);  lua_pushnumber(L, 20);  if(lua_pcall(L, 2, 1, 0) != 0){    printf("error %s\n", lua_tostring(L,-1));    return -1;  }  double z = lua_tonumber(L, -1);  printf("z = %f \n", z);  lua_pop(L, 1);  lua_close(L);  return 0;}

lua_pcall(L, 2, 1, 0)表示,傳入兩個參數,期望得到一個傳回值,0表示錯誤處理函數在棧中的索引值,壓入結果前會彈出函數和參數,所以z的索引是-1.

二、 lua調用C

lua可以將C函數註冊到lua中,C函數必須遵循統一的原型,這個原型定義在lua.h中,

typedef int (*) (lua_State *)

用C函數擴充lua時,一般將所有的C函數編譯成一個獨立的模組,方便增加新的函數。

//mylib.c#include <stdio.h>#include <lua.h>#include <lualib.h>#include <lauxlib.h>#include <math.h>static int myadd(lua_State *L){                int a = luaL_checknumber(L, 1);                int b = luaL_checknumber(L, 2);                lua_pushnumber(L, a+b);                return 1;}static const struct luaL_Reg mylib [] = {        {"add", myadd},         {NULL, NULL}};int luaopen_mylib(lua_State *L){  luaL_newlib(L, mylib);  return 1;}//call.lua#!/usr/local/bin/lualib=require "mylib"print(lib.add(1, 2))

每個被lua調用的C函數都有自己的私人棧,壓入參數的索引從1開始遞增,結果值也是直接壓入棧中,函數返回時會將壓入的參數全部刪除,只留下結果值。mylib[]聲明了模組中所有C函數列表,每一項映射了C函數在lua中的命名,比如上面代碼中myadd函數在lua中用add表示,列表必須用{NULL, NULL}結束。 luaL_newlib在棧中建立一個table,將mylib數組中的C函數註冊進這個table中。 luaopen_mylib將這個table中的函數載入進lua環境中。

先將C代碼編譯成動態連結程式庫,

gcc -shared -fPIC -o mylib.so mylib.c -llua -lm -ldl

lua代碼中,require會尋找 mylib.so,並調用該連結庫中的 luaopen_mylib,luaopen_的尾碼必須與動態連結程式庫名字一樣,這是由require尋找函數方式決定的。

lua編程之lua與C相互調用

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.