Lua 的強大在於其極簡的核心與靈活的模組機制。當內建庫無法滿足需求時,我們可以用 C 編寫高效能模組,經編譯為動態庫後透過 require 載入。本文以實作 libencode.sha1 為例,完整示範從 C 代碼編寫、編譯鏈接到部署載入的全流程。
-- test.lua require "libencode" local str = "source str" local des = libencode.sha1(str) print(des)
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
// 實際 SHA1 運算函數(此處略過演算法細節)
static void encode_sha(const char* src, char* des) {
/* SHA1 雜湊演算法實作 */
}
// Lua 可呼叫的 C 函數簽名:int func(lua_State* L)
static int l_sha1(lua_State* lua) {
const char *src = NULL;
char des[40] = {0}; // SHA1 輸出 40 字元十六進制字串
// 1. 從 Lua 棧取得第 1 個參數(字串)
src = luaL_checkstring(lua, 1);
// 2. 呼叫核心運算
encode_sha(src, des);
// 3. 將結果推入 Lua 棧
lua_pushstring(lua, des);
// 4. 回傳值個數(這裡回傳 1 個字串)
return 1;
}
// 函數映射表:Lua 函數名 ↔ C 函數指標
static const struct luaL_Reg encode[] = {
{"sha1", l_sha1},
{NULL, NULL} // 必須以 {NULL, NULL} 結尾
};
// 模組開啟函數:require "libencode" 時自動呼叫
int luaopen_libencode(lua_State* lua) {
// 註冊模組及其所有函數
luaL_register(lua, "libencode", encode);
return 1;
}
| API | 用途 | 關鍵說明 |
|---|---|---|
luaL_checkstring(L, idx) | 取得字串參數 | 自動檢查型別、轉換、報錯 |
lua_pushstring(L, s) | 推入字串結果 | 複製字串內容到 Lua 棧 |
luaL_register(L, name, reg) | 註冊模組 | 建立名為 name 的 table,填入 reg 陣列映射 |
luaopen_模組名 | 模組入口點 | 命名慣例:luaopen_ + 模組名 |
gcc -fPIC -shared -o libencode.so source.c -I/path/to/lua/include
# 查看 C 模組路徑 lua -e "print(package.cpath)" # 複製過去(假設路徑為 /usr/local/lib/lua/5.4/) cp libencode.so /usr/local/lib/lua/5.4/
lua test.lua # 應輸出 SHA1 雜湊值
.so 檔案位於 package.cpath 指定的路徑中,檔名需為 libencode.so(Linux)或 libencode.dll(Windows)。-llua),且確保 luaopen_libencode 函數名與模組名完全對應。luaL_check* 系列函數自動進行型別檢查。encode 陣列新增 md5、sha256 等映射。update(data)、final() 介面,避免一次性載入巨大字串。掌握 C 擴展 Lua 模組的開發流程,能讓你在嵌入式系統、遊戲腳本層、高效能網路服務等場景中,靈活結合 Lua 的開發效率與 C 的執行效能,實現兩全其美的架構設計。