lua5.3與c交互環境

聲明:本篇博客主要講解怎樣搭建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;
}

運行結果如圖所示:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章