我正在编写C代码来判断和修改lua中的 struct 成员,我使用元表

它适用于简单的定义,但在数组中我不能使其工作,我有以下代码

struct pinfo {
    int time;
    bool hide_name;
    int type_info[10];
};

struct mystruct {
    int id;
    int value;
    int option[20];
    struct pinfo pf[5];
    ....
};


int Get_mystruct(lua_State *L) {
    struct mystruct *ms = (struct mystruct*)lua_touserdata(L, 1);

    lua_pushlightuserdata(L, ms);
    luaL_getmetatable(L, "mystruct");
    lua_setmetatable(L, -2);

    return 1;
}

int mystruct_index(lua_State *L) {
    struct mystruct *ms = (struct mystruct*)lua_touserdata(L, 1);
    const char *field = lua_tostring(L, 2);


    if (strcmp(field, "id") == 0) {
        lua_pushinteger(L, ms->id);
    }
    else if (strcmp(field, "value") == 0) {
        lua_pushinteger(L, ms->value);
    }
    else if (strcmp(field, "option") == 0) {
        lua_pushinteger(L, ms->option[lua_tointeger(L, 3)]);
    }
    else {
        lua_pushnil(L);
    }

    return 1;
}
    
int mystruct_newindex(lua_State  *L) {
    struct mystruct *ms = (struct mystruct*)lua_touserdata(L, 1);
    const char *field = lua_tostring(L, 2);
    int value = (int)lua_tointeger(L, 3);


    if (strcmp(field, "id") == 0) {
        ms->id = value;
    }
    else if (strcmp(field, "value") == 0) {
        ms->value = value;
    }
    else if (strcmp(field, "option") == 0) {
        ms->option[lua_tointeger(L, 3)] = (int)lua_tointeger(L, 4);
    } else {
        lua_pushnil(L);
    }

    return 0;
}

void mystruct_create(lua_State *L) {
    luaL_Reg mystructData[] = {
        { "GetMyStruct", Get_mystruct},
        { "__index", mystruct_index},
        { "__newindex", mystruct_newindex},
        {NULL, NULL}
    };

    luaL_newmetatable(L, "mystruct");
    luaL_setfuncs(L, mystructData, 0);
    lua_setfield(L, -2, "MyStructLua");
}

在Lua中,我的用法如下

local ms = MyStructLua.GetMyStruct(my_ptr)

print(ms.id) // Returns 0, not defined
ms.id = 1000 
print(ms.id) // Returns 1000, has been defined

现在,当我go 定义数组时,例如,当我try 时出现问题

for o = 0, 19 do
    mp.option[o] = 1
end

当我设置该值时,出现错误bad argument #3 to 'index' (number expected, got no value)

我想知道如何在这个元表中使用简单和复杂的数组,我有struct,它是mystruct的成员数组,我如何将它添加到_newindex_index

推荐答案

Oka has pointed out表示a.b[o] = d包含两个索引操作,因此必须 for each 数组创建元表.顺便说一句,正如我在前面删除的问题中 comments 的那样,我建议您使用第三方库来完成绑定,因为它实现起来相当复杂.我先把pf字段放在一边,基本原理是一样的.让我们从一个错误开始:

lua_pushlightuserdata(L, ms);
luaL_getmetatable(L, "mystruct");
lua_setmetatable(L, -2);

这看起来很合理,但我相信结果不是你想要的,那是因为从the manual开始你可以读到:

表和完整的用户数据具有单独的元表,尽管多个表和用户数据可以共享它们的元表.所有其他类型的值对于每个类型共享一个元表;即there is one single metatable for all numbers, one for all strings, etc.默认情况下,值没有元表,但字符串库为字符串类型设置了一个元表.

如果为 struct 设置了元表mystruct,则不能为其他数组设置另一个元表.解决方案是创建完整的用户数据来存储 struct 和array.您只需要保存指针,所以我编写了两个函数来简化这些操作.

void newpointerud(lua_State* L, const char* mt, int nuv, const void* data) {
    auto p = (const void**)lua_newuserdatauv(L, sizeof(void*), nuv);
    luaL_setmetatable(L, mt);
    *p = data;
}

void* getpointerud(lua_State* L, int idx) {
    return *(void**)lua_touserdata(L, 1);
}

接下来,您需要为int[]编写相应的元方法,并创建一个元表.

// ..options[idx]
int mt_c_int_array_index(lua_State* L) {
    int* options = (int*)getpointerud(L, 1);
    int idx = lua_tointeger(L, 2);
    if (idx >= 0 && idx < 20)
        lua_pushinteger(L, *(options + idx));
    else
        lua_pushnil(L);
    return 1;
}

// ..options[idx] = value
int mt_c_int_array_newindex(lua_State* L) {
    int* options = (int*)getpointerud(L, 1);
    int idx = lua_tointeger(L, 2);
    if (idx >= 0 && idx < 20)
        *(options + idx) = lua_tointeger(L, 3);
    else
        luaL_error(L, "Out of index");
    return 0;
}

.....
luaL_Reg mt_c_int_array[] = {
    { "__index", mt_c_int_array_index },
    { "__newindex", mt_c_int_array_newindex },
    {NULL, NULL}
};
luaL_newmetatable(L, "mt_c_int_array");
luaL_setfuncs(L, mt_c_int_array, 0);

第三,使用完整的用户数据来打包您的 struct 和array.在这里,您通常不希望在每次访问option数组时都创建新的用户数据.您可以使用用户数据的用户值来预保存选项数组的用户数据.

newpointerud(L, "mystruct", 1, ms); // 1 user value
newpointerud(L, "mt_c_int_array", 0, ms->option);
lua_setiuservalue(L, -2, 1);

最后,在您的mystruct_index函数中,返回该用户值.

....
else if (strcmp(field, "option") == 0) {
    lua_getiuservalue(L, 1, 1);
}
....

C++相关问答推荐

ATmega328P USART发送字符重复打印

sizeof结果是否依赖于字符串的声明?

在使用GTK 4 Columnview列表模型时,如何为多列添加排序函数.C编码,Linux/GNOME环境

丑陋的三重间接:可扩展的缓冲区管理 struct

在C中使用动态内存分配找到最小的负数

为什么GCC可以调用未定义的函数?

__VA_OPT__(,)是否可以检测后面没有任何内容的尾随逗号?

编译的时候g++通常会比GCC慢很多吗?

在列表中插入Int指针(C)

接受任何参数的函数指针是否与接受不同参数的函数兼容

C标准关于外部常量的说明

将 struct 数组写入二进制文件时发生Valgrind错误

C中的回文数字

如何逐位读取二进制文件?

Fscanf打印除退出C代码为1的程序外的所有内容

try 查找带有指针的数组的最小值和最大值

将数组中的所有元素初始化为 struct 中的相同值

如何用用户输入的多个字符串填充数组?

将字节/字符序列写入标准输出的最简单形式

为什么这里的符号没有解析?