如何将C中长字符串的指针传递给Lua并正常使用?
解决C语言传递长字符串指针到Lua的问题
我来帮你搞定这个问题~你遇到的核心问题是:lua_pushlightuserdata 传入的只是一个无类型的内存指针,Lua本身不知道它指向的是字符串,所以没法直接操作它的内容。下面给你两种实用的解决方案:
方案一:给Lua提供C函数读取指针内容
这种方法最简单直接,我们在C里写一个辅助函数,让Lua可以传入指针和字符串长度,然后返回对应的字符串内容。
C代码示例
#include <lua.h> #include <lauxlib.h> #include <lualib.h> #include <string.h> // 从指针获取字符串的辅助函数 static int l_get_string_from_ptr(lua_State *L) { // 取出传入的lightuserdata(字符串指针)和长度 const char *str_ptr = (const char *)lua_touserdata(L, 1); size_t str_len = luaL_checkinteger(L, 2); // 将字符串内容push到Lua栈,返回给Lua lua_pushlstring(L, str_ptr, str_len); return 1; // 告诉Lua我们返回了1个值 } // 注册自定义函数到Lua库 static const struct luaL_Reg mylib[] = { {"get_string_from_ptr", l_get_string_from_ptr}, {NULL, NULL} // 结束标记 }; int luaopen_mylib(lua_State *L) { luaL_newlib(L, mylib); return 1; } // 测试用的主函数 int main() { lua_State *L = luaL_newstate(); luaL_openlibs(L); // 加载我们的自定义库,并设置为全局变量mylib luaopen_mylib(L); lua_setglobal(L, "mylib"); // 模拟一个超长字符串 const char *long_str = "这是一个非常非常长的字符串,省略一万字...实际场景中可能是从文件读取或者动态生成的大内容"; size_t str_len = strlen(long_str); // 将指针和长度传入Lua,执行Lua代码 lua_pushlightuserdata(L, (void *)long_str); lua_pushinteger(L, str_len); luaL_dostring(L, "local ptr, len = ... local content = mylib.get_string_from_ptr(ptr, len) print('字符串前50个字符:', content:sub(1, 50))"); lua_close(L); return 0; }
Lua代码示例
-- 接收C传入的指针和长度 local ptr, len = ... -- 通过自定义函数获取字符串内容 local full_str = mylib.get_string_from_ptr(ptr, len) -- 现在可以正常操作字符串了 print("字符串总长度:", len) print("字符串最后100个字符:", full_str:sub(-100))
方案二:封装成带元表的userdata(更优雅)
如果想让Lua里的使用更自然,可以把指针和长度打包成一个带元表的userdata,给它定义tostring方法,让Lua可以直接把它当成字符串来处理。
补充的C代码部分
// 定义存储字符串指针和长度的结构体 typedef struct { const char *ptr; size_t len; } StringRef; // 给StringRef定义__tostring方法,返回完整字符串 static int l_stringref_tostring(lua_State *L) { StringRef *ref = (StringRef *)luaL_checkudata(L, 1, "StringRef"); lua_pushlstring(L, ref->ptr, ref->len); return 1; } // StringRef的元表方法 static const struct luaL_Reg stringref_meta[] = { {"__tostring", l_stringref_tostring}, {NULL, NULL} }; // 创建StringRef的函数 static int l_create_stringref(lua_State *L) { const char *ptr = (const char *)lua_touserdata(L, 1); size_t len = luaL_checkinteger(L, 2); // 分配userdata内存 StringRef *ref = (StringRef *)lua_newuserdata(L, sizeof(StringRef)); ref->ptr = ptr; ref->len = len; // 设置元表 luaL_getmetatable(L, "StringRef"); lua_setmetatable(L, -2); return 1; } // 更新库的注册列表 static const struct luaL_Reg mylib[] = { {"get_string_from_ptr", l_get_string_from_ptr}, {"create_stringref", l_create_stringref}, {NULL, NULL} }; int luaopen_mylib(lua_State *L) { // 创建并初始化StringRef的元表 luaL_newmetatable(L, "StringRef"); luaL_setfuncs(L, stringref_meta, 0); lua_pop(L, 1); // 把元表从栈里弹出 luaL_newlib(L, mylib); return 1; }
对应的Lua使用代码
local ptr, len = ... -- 创建StringRef对象 local str_ref = mylib.create_stringref(ptr, len) -- 直接转成字符串使用 print("完整字符串:", tostring(str_ref)) -- 或者截取部分内容 print("前30个字符:", tostring(str_ref):sub(1, 30))
重要注意事项
- 内存有效性:确保指针指向的内存在Lua使用期间不会被释放或修改,否则会导致未定义行为。如果是动态分配的内存,记得给userdata添加
__gc元方法来自动释放。 - 字符串长度:一定要传递字符串的真实长度,不要依赖
strlen(如果字符串包含\0的话,strlen会提前终止)。
内容的提问来源于stack exchange,提问作者sharafi
相关产品推荐
相关产品推荐

