gpt4 book ai didi

c++ - 除非复制到新字符串,否则比较从 Lua 中的 C 函数推送的字符串失败

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:02:26 27 4
gpt4 key购买 nike

我正在开发一个程序,该程序在使用 C 和 C++ 混合编写的 SDL 窗口中创建 Lua 5.1 环境。我已经设置了一个事件系统来对 SDL 事件进行排队,以便 Lua 可以从队列中弹出事件。当键入可打印字符时发送事件之一。当检测到事件时,它会将字符串插入新的 lua_State,将其放入 std::queue 队列中,一旦将值拉入 lua_State 被复制到主协程状态,然后由 coroutine.yield 返回。但是当我将字符串与 Lua 端的常量进行比较时(例如:ev[2] == "q"),比较结果为 false。如果我将该值复制到新字符串并进行比较(例如:"".. ev[2] == "q"),比较结果为真。

我尝试过使用多种方式来推送字符串(因为 SDL 提供的是 UTF-8 字符串而不是 ASCII 字符),包括:

  • lua_pushstring(L, e.text.text)
    插入整个字符串
  • lua_pushlstring(L, e.text.text, 1)
    插入第一个字符
  • char tmp[2]; tmp[0] = e.text.text[0]; tmp[1] = 0; lua_pushstring(L, tmp)
    复制字符串并插入

但这些都没有解决问题。

这是我的 C++ 代码中的基本结构:

const char * termGetEvent(lua_State *L) {
SDL_Event e;
if (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) return "die";
else if (e.type == SDL_KEYDOWN && keymap.find(e.key.keysym.scancode) != keymap.end()) {
lua_pushinteger(L, keymap.at(e.key.keysym.scancode));
lua_pushboolean(L, false);
return "key";
} else if (e.type == SDL_KEYUP && keymap.find(e.key.keysym.scancode) != keymap.end()) {
lua_pushinteger(L, keymap.at(e.key.keysym.scancode));
return "key_up";
} else if (e.type == SDL_TEXTINPUT) { // this is the section producing errors
char tmp[2];
tmp[0] = e.text.text[0];
tmp[1] = 0;
lua_pushstring(L, tmp);
return "char";
} else if (e.type == SDL_MOUSEBUTTONDOWN) {
lua_pushinteger(L, buttonConvert(e.button.button));
lua_pushinteger(L, convertX(e.button.x));
lua_pushinteger(L, convertY(e.button.y));
return "mouse_click";
} else if (e.type == SDL_MOUSEBUTTONUP) {
lua_pushinteger(L, buttonConvert(e.button.button));
lua_pushinteger(L, convertX(e.button.x));
lua_pushinteger(L, convertY(e.button.y));
return "mouse_up";
} else if (e.type == SDL_MOUSEWHEEL) {
int x = 0, y = 0;
term->getMouse(&x, &y);
lua_pushinteger(L, e.button.y);
lua_pushinteger(L, convertX(x));
lua_pushinteger(L, convertY(y));
return "mouse_scroll";
} else if (e.type == SDL_MOUSEMOTION && e.motion.state) {
lua_pushinteger(L, buttonConvert2(e.motion.state));
lua_pushinteger(L, convertX(e.motion.x));
lua_pushinteger(L, convertY(e.motion.y));
return "mouse_drag";
} else if (e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_RESIZED) {
term->resize();
}
}
return NULL;
}

std::queue<std::pair<const char *, lua_State*> > eventQueue;

int getNextEvent(lua_State *L, const char * filter) {
std::pair<const char *, lua_State*> ev;
do {
while (eventQueue.size() == 0) {
lua_State *param = luaL_newstate();
if (!lua_checkstack(param, 4)) printf("Could not allocate event\n");
const char * name = termGetEvent(param);
if (name != NULL) {
if (strcmp(name, "die") == 0) running = 0;
eventQueue.push(std::make_pair(name, param));
} else if (param) {
lua_pushnil(param);
lua_close(param);
param = NULL;
}
}
ev = eventQueue.front();
eventQueue.pop();
} while (strlen(filter) > 0 && strcmp(std::get<0>(ev), filter) != 0);
// Copy the next event in
lua_State *param = std::get<1>(ev);
int count = lua_gettop(param);
if (!lua_checkstack(L, count + 1)) printf("Could not allocate\n");
lua_pushstring(L, std::get<0>(ev));
lua_xmove(param, L, count);
//lua_close(param);
return count + 1;
}

lua_State *L;

int main() {
int status, result, i;
double sum;
lua_State *coro;
start:
/*
* All Lua contexts are held in this structure. We work with it almost
* all the time.
*/
L = luaL_newstate();

coro = lua_newthread(L);

luaL_openlibs(coro); /* Load Lua libraries */
termInit(); // initializes SDL

/* Load the file containing the script we are going to run */
status = luaL_loadfile(coro, bios_path);
if (status) {
/* If something went wrong, error message is at the top of */
/* the stack */
fprintf(stderr, "Couldn't load file: %s\n", lua_tostring(L, -1));
exit(1);
}
tid = createThread(&termRenderLoop); // stops when running != 1

/* Ask Lua to run our little script */
status = LUA_YIELD;
int narg = 0;
while (status == LUA_YIELD && running == 1) {
status = lua_resume(coro, narg);
if (status == LUA_YIELD) {
if (lua_isstring(coro, -1)) narg = getNextEvent(coro, lua_tostring(coro, -1));
else narg = getNextEvent(coro, "");
} else if (status != 0) {
running = 0;
joinThread(tid);
//usleep(5000000);
termClose();
printf("%s\n", lua_tostring(coro, -1));
lua_close(L);
exit(1);
}
}

joinThread(tid);
termClose();
lua_close(L); /* Cya, Lua */

if (running == 2) {
//usleep(1000000);
goto start;
}

return 0;
}

这是我用来测试的 Lua 脚本:

while true do
local ev = {coroutine.yield()}
print(table.unpack(ev)) -- provided by previous scripts
if ev[1] == "char" then
print("\"" .. ev[2] .. "\"") -- prints "q" if 'q' was pressed
assert(ev[2] == "q") -- false, even if 'q' was pressed
assert(string.len(ev[2]) == 1) -- true
assert(#ev[2] == 1) -- true
assert(string.len(string.sub(ev[2], 2, 2)) == 0) -- true
assert(string.sub(ev[2], 1, 1) == ev[2]) -- false
assert("" .. ev[2] == "q") -- true if 'q' was pressed
end
if ev[1] == "char" and string.sub(ev[2], 1, 1) == "q" then break end
end

我希望脚本中的所有 assert 都产生 true(假设按下“q”),但其中一些会产生 false。我不得不调整带有中断的语句以仅使用第一个字符。为什么没有正确比较字符串?

编辑:我不是要比较 C++ 端的字符串,而是要比较 Lua 端的字符串。我在 C 代码 (strcmp) 中正确处理字符串比较。

最佳答案

按照 Egor Skriptunoff 的建议将 luaL_newstate 替换为 lua_newthread,并将 lua_close 调用替换为 lua_pop,我能够解决问题。 This post在 lua-users 邮件列表上说你不能关闭一个新线程:

Graham Wakefield wrote:

Hi,

I'm having some hard to understand behavior; I create new threads using lua_newthread, and lua_resume them periodically from C++. However, I may wish to at some point terminate a thread before it has completed; I tried calling lua_close() on the thread's lua_State,

你不能在线程上调用 lua_close();仅在主要状态上。

这最终导致了段错误。因为否则我会过度使用内存,所以我最终将 lua_close 替换为 lua_pop 因为状态被推送到主堆栈上。应用这些修复程序后,我不再遇到任何段错误并且内存使用量保持不变。

关于c++ - 除非复制到新字符串,否则比较从 Lua 中的 C 函数推送的字符串失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57122266/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com