ESP32中Lua-C-API调用Lua函数出现空值调用错误求助
嘿,我帮你揪出这个错误的根源啦!你碰到的Unprotected error in call to Lua API (attempt to call a null value),核心问题是你只加载了Lua脚本,但没执行它——add.lua里的add函数根本没被注册到Lua状态机的全局环境中,所以lua_getglobal(L, "add")拿到的是nil,调用空值肯定会报错。下面一步步给你修复:
1. 补上Lua脚本的执行步骤
你现在的代码只用了luaL_loadfile,这个函数只是把Lua文件编译成字节码压到栈上,并没有执行。必须调用lua_pcall来运行这段字节码,这样add函数才会变成全局变量。修改加载文件的代码:
/* load Lua file */ if (luaL_loadfile(L, "add.lua")){ printf("Error loading file: %s", lua_tostring(L, -1)); lua_close(L); // 出错别忘了清理Lua状态机 return; } // 执行编译后的Lua脚本,注册add函数到全局环境 if (lua_pcall(L, 0, 0, 0) != LUA_OK) { printf("Error executing file: %s", lua_tostring(L, -1)); lua_close(L); return; }
2. 删掉重复的库初始化代码
你已经调用了luaL_openlibs(L),这个函数会自动加载所有Lua标准库(base、table、io、string、math这些全包含了),后面重复写的luaopen_base(L)、luaopen_table(L)完全多余,甚至可能引发冲突,直接删掉就行:
/* initialize Lua */ lua_State* L = luaL_newstate(); luaL_openlibs(L); // 删掉下面这些重复的代码 // openlibs(L); // 如果这个不是你自定义的函数,也建议检查下用途 // luaopen_base(L); // luaopen_table(L); // luaopen_io(L); // luaopen_string(L); // luaopen_math(L);
3. 确认Lua文件的路径和烧录情况
在ESP32上,你得确保add.lua已经正确烧录到设备的文件系统(比如SPIFFS或FATFS)里,而且路径和你代码里写的"add.lua"一致。如果文件放在子目录,路径要写完整(比如"/data/add.lua")。
可以加个小检查,确认文件存在:
#include <sys/stat.h> struct stat st; if (stat("add.lua", &st) != 0) { ESP_LOGE(TAG, "Oh no! add.lua file not found!"); }
4. 给lua_call加个安全检查
为了避免以后再踩类似的坑,建议在调用函数前先检查拿到的是不是函数类型:
int luaadd (lua_State* L, int x, int y ) { int sum; /* 获取全局函数add */ lua_getglobal(L, "add"); // 检查栈顶是不是函数 if (!lua_isfunction(L, -1)) { printf("Error: 'add' is not a function or not defined!"); lua_pop(L, 1); // 弹出栈上的nil,避免栈不平衡 return -1; // 返回错误码提示调用方 } /* 压入参数 */ lua_pushnumber(L, x); lua_pushnumber(L, y); /* 调用函数:2个参数,1个返回值 */ lua_call(L, 2, 1); /* 获取结果 */ sum = (int)lua_tointeger(L, -1); lua_pop(L, 1); return sum; }
修复后的app_main核心片段
void app_main() { initialize_nvs(); #if CONFIG_STORE_HISTORY initialize_filesystem(); #endif initialize_console(); /* 初始化Lua状态机 */ lua_State* L = luaL_newstate(); luaL_openlibs(L); /* 加载并执行Lua脚本 */ if (luaL_loadfile(L, "add.lua")){ printf("Error loading file: %s", lua_tostring(L, -1)); lua_close(L); return; } if (lua_pcall(L, 0, 0, 0) != LUA_OK) { printf("Error executing file: %s", lua_tostring(L, -1)); lua_close(L); return; } /* 调用add函数 */ int sum = luaadd(L, 10, 15 ); printf( "The sum is %d\n", sum ); /* 清理资源 */ lua_close(L); printf("Finished"); }
最后总结
这个问题本质就是加载了Lua脚本但没执行,导致全局函数没被注册。按上面的步骤改完,应该就能正常调用add函数了。另外一定要确认add.lua的路径和烧录情况,别因为文件找不到白忙活一场~
内容的提问来源于stack exchange,提问作者777




