8Programming in Lua(第4版)

C API

与C交互

lua_State栈操作C函数注册错误处理

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第8章:C API

一、导读

1.1 本章学习目标

第8章讲解 Lua 的 C API:如何在 C 中嵌入 Lua、如何注册 C 函数给 Lua 调用。

本章核心学习目标:

  • 理解 lua_State:Lua 环境的核心
  • 掌握栈操作:push、pop、get、set
  • 掌握 C 函数注册
  • 理解错误处理

1.2 为什么本章如此重要

C API 是 Lua 嵌入和扩展的基础。游戏引擎、高性能库都通过 C API 与 Lua 交互。

1.3 核心问题引导

lua_State 是什么?为什么每个线程需要一个?

Lua 栈如何工作?

如何从 C 调用 Lua 函数?


二、核心概念详解

2.1 lua_State 和栈

c
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

// 创建 Lua 环境
lua_State *L = luaL_newstate();
luaL_openlibs(L);  // 打开标准库

// 栈操作
lua_pushnumber(L, 3.14);    // 压入数字
lua_pushstring(L, "hello"); // 压入字符串
lua_pushboolean(L, 1);      // 压入布尔值

// 获取栈顶元素
double n = lua_tonumber(L, -1);
const char* s = lua_tostring(L, -2);

// 弹出
lua_pop(L, 1);

// 栈大小
int top = lua_gettop(L);

lua_close(L);

2.2 注册 C 函数

c
// C 函数签名: int func(lua_State *L)
// 返回值个数

int l_add(lua_State *L) {
    double a = luaL_checknumber(L, 1);
    double b = luaL_checknumber(L, 2);
    lua_pushnumber(L, a + b);
    return 1;  // 返回 1 个值
}

// 注册到 Lua
lua_pushcfunction(L, l_add);
lua_setglobal(L, "add");

// 在 Lua 中使用:
// print(add(3, 4))  -- 7

// 批量注册
static const luaL_Reg mylib[] = {
    {"add", l_add},
    {"sub", l_sub},
    {"mul", l_mul},
    {NULL, NULL}
};

luaL_newlib(L, mylib);
lua_setglobal(L, "mylib");

2.3 调用 Lua 函数

c
// 调用 Lua 函数
lua_getglobal(L, "myFunction");  // 获取函数
lua_pushnumber(L, 42);           // 参数 1
lua_pushstring(L, "hello");      // 参数 2

// lua_pcall(L, nargs, nresults, errfunc)
int status = lua_pcall(L, 2, 1, 0);
if (status != LUA_OK) {
    const char* error = lua_tostring(L, -1);
    printf("Error: %s\n", error);
    lua_pop(L, 1);
} else {
    double result = lua_tonumber(L, -1);
    printf("Result: %g\n", result);
    lua_pop(L, 1);
}

三、实战案例

3.1 案例一:嵌入 Lua 脚本引擎

c
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <stdio.h>

// C 函数: 打印日志
int l_log(lua_State *L) {
    const char* level = luaL_checkstring(L, 1);
    const char* msg = luaL_checkstring(L, 2);
    printf("[%s] %s\n", level, msg);
    return 0;
}

int main() {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    
    // 注册 C 函数
    lua_pushcfunction(L, l_log);
    lua_setglobal(L, "log");
    
    // 执行 Lua 脚本
    if (luaL_dofile(L, "script.lua") != LUA_OK) {
        printf("Error: %s\n", lua_tostring(L, -1));
    }
    
    lua_close(L);
    return 0;
}

// script.lua:
// log("INFO", "Application started")
// log("DEBUG", "Loading resources...")

四、本章小结

lua_State 是 Lua 环境的核心

栈是 C 和 Lua 之间通信的桥梁

C 函数通过栈接收参数和返回值


五、思考与练习

为什么 Lua 使用栈而非直接传参?

如何处理 C 函数中的 Lua 异常?


8/8C AP
0%