聲明:本篇博客主要講解怎樣搭建lua和c交互環境。具體lua和c之間怎麼交互調用,可以參考lua5.3程序設計進階。
c調用lua操作時,環境配置如下:
1.新建vs c++空工程,如圖所示:
2.下載lua5.3.5的源碼並將src目錄下的所有文件放入到步驟1中創建的工程裏面。如圖所示:
3.編寫一個簡單的lua庫文件test.lua。代碼如下所示:
-- 這是註釋
width=2009
height=3009
4.將lua.c以及luac.c等文件中的main函數註釋掉,然後新建一個test.c文件。如圖所示:
5.編寫test.c文件。在該文件中啓動lua虛擬機加載lua庫文件並取出數值進行輸出。
代碼如下所示:
#include <stdio.h>
#include <stdlib.h>
#include "lua.h"
#include "lauxlib.h"
void error(lua_State* L, const char* fmt, ...)
{
// 將可變長參數的錯誤信息填充到標準錯誤輸出流中
va_list argp;
va_start(argp, fmt);
vfprintf(stderr, fmt, argp);
va_end(argp);
lua_close(L);
// 由於調用exit時看不到輸出結果,所以此處用死循環代替
//exit(EXIT_FAILURE);
while (1) {}
}
int getglobint(lua_State* L, const char* var)
{
int isnum, result;
// 將全局變量var的值壓入棧,並返回該值得類型
int vt = lua_getglobal(L, var);
printf("vt:%d\n", vt);
// 嘗試將棧頂元素值轉換成整形,失敗時拋出錯誤,成功時就彈出棧並返回
result = lua_tointegerx(L, -1, &isnum);
if (!isnum)
{
error(L, "'%s' should be a number!\n", var);
}
lua_pop(L, -1);
return result;
}
void load(lua_State* L, const char* filename)
{
// 加載指定filename文件內容並編譯成lua代碼塊,然後執行該lua代碼塊
// 加載或者調用失敗時會返回非0錯誤碼,並且lua虛擬機會往棧頂壓入錯誤信息。
if (luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
{
error(L, "cannot run config.file:%s", lua_tostring(L, -1));
}
// 輸出lua庫文件中全局的變量width和height值
printf("w=%d, h=%d", getglobint(L, "width"), getglobint(L, "height"));
}
int main(void)
{
lua_State* L = luaL_newstate();
// 第二個參數爲lua庫文件
load(L, "C:/Users/DELL.DESKTOP-J1LR5AC/Desktop/test.lua");
// 死循環的目的是爲了看到輸出
while (1) {};
return 0;
}
運行結果如圖所示:
lua調用c操作時,環境配置如下:
1.新建vs c++空工程,如圖所示:
2.下載lua5.3.5的源碼並將src目錄下的所有文件放入到步驟1中創建的工程裏面。如圖所示:
3.將lua.c以及luac.c等文件中的main函數註釋掉,然後新建一個解釋器luaex.c文件。如圖所示:
4.lua調用c函數有兩種方式,分別如下:
4.1.1.編寫luaex.c文件。在該文件中通過調用lua_pushcfunction和lua_setglobal函數將c函數l_sin賦值給lua全局變量mysin。然後解釋執行包含mysin調用的lua代碼(lua代碼從終端輸入)。
代碼如下所示:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
// 要註冊給lua端使用的c端函數
// return:返回值個數
static int l_sin(lua_State* L)
{
// 獲取lua端傳遞到當前c函數的參數
double d = lua_tonumber(L, 1);
// 調用sin函數獲取一個正弦值並壓入棧中
lua_pushnumber(L, sin(d));
// 返回值個數
return 1;
}
int main(void)
{
// 創建lua虛擬機對象,使用默認內存分配函數
lua_State* L = luaL_newstate();
// 註冊所有預定義的標準庫(debug,string,table,io等)供lua端使用
luaL_openlibs(L);
// 壓入c函數到棧頂
lua_pushcfunction(L, l_sin);
// 將棧頂的c函數注入到lua的全局變量mysin中
lua_setglobal(L, "mysin");
int error = 0;
// 從標準輸入流中獲取lua代碼
char buff[256];
while (fgets(buff, sizeof(buff), stdin) != NULL)
{
// 加載lua代碼並編譯成lua函數代碼塊,然後調用該函數。成功返回0,否則返回非0並將錯誤信息壓棧
error = luaL_loadstring(L, buff) || lua_pcall(L,0, 0, 0);
if (error)
{
// 從棧中獲取錯誤信息輸出後再彈出
fprintf(stderr, "%s\n", lua_tostring(L, -1));
lua_pop(L,1);
}
}
// 沒有lua代碼時就關閉lua虛擬機
lua_close(L);
return 0;
}
運行結果如圖所示:
4.2.1.新建&編寫c模塊文件lmuslib。
新建如圖所示:
代碼如下所示:
#include <math.h>
#include "lua.h"
#include "lauxlib.h"
// 要註冊給lua端使用的c端函數
// return:返回值個數
static int mus_sin(lua_State* L)
{
// 獲取lua端傳遞到當前c函數的參數
double d = luaL_checknumber(L, 1);
// 調用sin函數獲取一個正弦值並壓入棧中
lua_pushnumber(L, sin(d));
// 返回值個數
return 1;
}
// 註冊數組:格式爲{lua函數名稱, c函數地址},以{NULL, NULL}結束。
static const struct luaL_Reg muslib[] = {
{"sin", mus_sin},
{NULL, NULL} // 哨兵,也就是結束標識
};
// 定義一個打開函數"luaopen_mus"。可以被"require mus"以靜態或者動態庫的形式調用
// 也可以在編譯lua解釋器直接調用。
LUAMOD_API int luaopen_mus(lua_State* L)
{
// 創建一個新的表,並將muslib中的lua函數名-函數地址填充該表
luaL_newlib(L, muslib);
// 返回一個結果,將新創建的表賦值給模塊名變量
return 1;
}
4.2.2.在lualib.h文件中定義模塊名宏LUA_MUSNAME以及聲明c模塊打開函數luaopen_mus。如圖所示:
4.2.3.在linit.c文件中的loadedlibs數組中添加模塊名宏LUA_MUSNAME以及c模塊打開函數luaopen_mus。如圖所示:
4.2.4.編寫luaex.c文件。在該文件中通過調用luaL_openlibs函數將lua函數名sin和c函數mus_sin以表的形式賦值給模塊名變量mus。然後解釋執行包含mus.sin調用的lua代碼(lua代碼從終端輸入)。
編寫代碼如下所示:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
int main(void)
{
// 創建lua虛擬機對象,使用默認內存分配函數
lua_State* L = luaL_newstate();
// 註冊所有預定義的標準庫(debug,string,table,io等)供lua端使用
luaL_openlibs(L);
int error = 0;
// 從標準輸入流中獲取lua代碼
char buff[256];
while (fgets(buff, sizeof(buff), stdin) != NULL)
{
// 加載lua代碼並編譯成lua函數代碼塊,然後調用該函數。成功返回0,否則返回非0並將錯誤信息壓棧
error = luaL_loadstring(L, buff) || lua_pcall(L,0, 0, 0);
if (error)
{
// 從棧中獲取錯誤信息輸出後再彈出
fprintf(stderr, "%s\n", lua_tostring(L, -1));
lua_pop(L,1);
}
}
// 沒有lua代碼時就關閉lua虛擬機
lua_close(L);
return 0;
}
運行結果如圖所示: