我正在尝试使用Lua C API创建一个userdata,其中有一个metatable关联,我将收集一个矩阵。
我不能得到的是如何将初始化矩阵的每个分量设置为零。
我正如我在此描述的那样编译我的Lua模块C代码。
我的C代码如下:
#include "lauxlib.h" #include "lua.h" typedef struct { LUA_NUMBER data[1][1]; int row; int col; }matrix; // Create a matrix full of zeros static int lb_newmatrix(lua_State *L) { // Variable declarations int i,j; matrix *temp; // Input checks if (lua_gettop(L)!=2) { lua_pushstring(L,"n Two input required"); lua_error(L); } //--> Check I° index m riga luaL_checktype(L,1,LUA_TNUMBER); if (lua_tonumber(L,1) Check II° index n colonna luaL_checktype(L,2,LUA_TNUMBER); if (lua_tonumber(L,2)row = m; temp->col = n; // Matrix inizialization /* PROBLEM HERE */ for (i=1;i==m;i++) { for(j=1;j==n;j++) { temp->data[i][j] = 0; } } //------------------------------- // If I de-comment these line, // the matrix is written but // element with equal sum indices // rewrite!!! //------------------------------- // temp->data[1][1] = nbyte; // temp->data[1][2] = nbyte2; // temp->data[1][3] = 13; // temp->data[2][1] = nbyte2; // temp->data[2][2] = 22; // temp->data[2][3] = 23; // temp->data[3][1] = 31; // temp->data[3][2] = 32; // temp->data[3][3] = 33; // Link the userdata to the metatable "basic" luaL_getmetatable(L,"basic"); lua_setmetatable(L,-2); return 1; } static int lb_index(lua_State *L) { /* Check input Numbers */ if (lua_gettop(L)>3) { lua_pushstring(L,"nOnly two inputs are needed:n1) Pointn2) N° rown3) N° col"); lua_error(L); } /* Check if the first input is userdata basic */ matrix *temp = (matrix *)luaL_checkudata(L,1,"basic"); /* I° index check ROW */ luaL_checktype(L,2,LUA_TNUMBER); if (lua_tointeger(L,2)temp->row) { lua_pushstring(L,"n First index should be 1 to n"); lua_error(L); } /* II° index check COLUMN */ luaL_checktype(L,3,LUA_TNUMBER); if (lua_tointeger(L,3)temp->col) { lua_pushstring(L,"n Second index should be 1 to m"); lua_error(L); } int row = lua_tointeger(L,2); int col = lua_tointeger(L,3); /* Insert the index value of userdata on top of the stack */ lua_pushnumber(L,temp->data[row][col]); return 1; } /********************** * MODULE DECLARATION * **********************/ static const struct luaL_Reg LuaBasic_f [] = {// {"NewMatrix",lb_newmatrix}, { "__index", lb_index}, { NULL, NULL}}; static const struct luaL_Reg LuaBasic_m [] = {// { NULL, NULL}}; LUA_API int luaopen_LuaBasic(lua_State *L) { /* Insert basic metatable "basic" into the stack */ luaL_newmetatable(L,"basic"); /* Copy the "basic" metatable and push it into the stack */ lua_pushvalue(L,-1); /* basic["__index"] = basic */ lua_setfield(L,-2,"__index"); /* register all the function into LuaBasic_m into the basic table metatable */ luaL_setfuncs(L,LuaBasic_m,0); luaL_newlib(L,LuaBasic_f); return 1; }
相关的Lua代码如下:
lb = require("LuaBasic") A = lb.NewMatrix(3,3) print(A) print("--------------") print(lb.__index(A,1,1)) print(lb.__index(A,1,2)) print(lb.__index(A,1,3)) print(lb.__index(A,2,1)) print(lb.__index(A,2,2)) print(lb.__index(A,2,3)) print(lb.__index(A,3,1)) print(lb.__index(A,3,2)) print(lb.__index(A,3,3)) print("--------------") print("row = "..lb.GetRow(A)) print("col = "..lb.GetCol(A))
我得到的输出是:
userdata: 007C2940 -------------- 1.#QNAN 1.#QNAN 1.#QNAN 1.#QNAN 1.#QNAN 1.#QNAN 1.#QNAN 1.#QNAN 1.#QNAN -------------- row = 3 col = 3
我不明白为什么我不能将零值写入初始化矩阵。
我做错了什么?
好吧,你怎么能找到答案? 您可以启动调试器并查看内存中的数据。 或者……这是Lua,您可以扩展您的库以使其变得简单。 所以,如果你想跟随…(否则只是跳过引用块)
在
lb_newmatrix
结束时(就在return
之前),添加lua_pushinteger( L, nbyte );
并改变return 1;
return 2;
。 (这只是方便,所以我们不必重新计算尺寸。)此外,添加static int lb_peek( lua_State *L ) { int nbytes = luaL_checkinteger( L, 2 ); char *data = (char*)luaL_checkudata(L,1,"basic"); lua_pushlstring( L, data, nbytes ); return 1; }
并将该函数添加到
LuaBasic_m
中{"peek",lb_peek}
。 重新编译,启动Lua解释器并加载库。> m, size = lb.NewMatrix( 3, 3 ) -- make a small matrix > data = m:peek( size ) -- get the memory as a string > (("n "):rep(3*3).."II"):unpack( data ) -- and unpack the values 0.0 6.366e-314 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 81 -- (note: the trailing '81' is the offset of the next character in -- the string beyond what was read and not part of your data) -- so your matrix looks like: -- 0.0 6.366e-314 0.0 -- 0.0 0.0 0.0 -- 0.0 0.0 0.0 -- and has 0 rows and 0 columns (according to the data…)
这看起来不正确……
6.366e-314
应该不存在。 让我们来看看整数看起来像什么……> size/4 20 > (("I4"):rep(20)):unpack( data ) 0 0 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 81
A-ha …你的矩阵尺寸在错误的地方! (参见数据区中间的3,3?)
你告诉编译器有一个1×1的LUA_NUMBER
数组……然后继续把它做大。 编译器发出的代码假定,给定matrix *m
, m->row
位于*(m+sizeof(LUA_NUMBER[1][1]))
但这就是你编写数据的地方……
因此,您需要更改struct
域的顺序: 保持可变大小的部分最后!
typedef struct { int row; int col; LUA_NUMBER data[1][1]; } matrix;
更改,重新编译和重新启动Lua后,我们可以检查:
> m, size = lb.NewMatrix( 3, 3 ) > data = m:peek( size ) > ("II"..("n "):rep(3*3)):unpack( data ) 3 3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 81
这是一个适当的全零3×3矩阵。 现在让我们检查一下数据的位置。 因为我们不想一直重新编译以测试新的分配,所以添加
/* m[i][j] = v */ static int lb_set( lua_State *L ) { matrix *m = (matrix*)luaL_checkudata(L,1,"basic"); int i = luaL_checkinteger( L, 2 ); int j = luaL_checkinteger( L, 3 ); lua_Number v = luaL_checknumber( L, 4 ); m->data[i][j] = v; return 0; }
并将
{"set",lb_set}
到LuaBasic_m
。 重新编译,重新加载:> m, size = lb.NewMatrix( 3, 3 ) > for i = 0, 2 do for j = 0, 2 do >> m:set( i, j, (i+1) + (j+1)/10 ) >> print( ("II"..("n "):rep(3*3)):unpack( m:peek( size ) ) ) >> end end 3 3 1.1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 81 3 3 1.1 1.2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 81 3 3 1.1 1.2 1.3 0.0 0.0 0.0 0.0 0.0 0.0 81 3 3 1.1 2.1 1.3 0.0 0.0 0.0 0.0 0.0 0.0 81 3 3 1.1 2.1 2.2 0.0 0.0 0.0 0.0 0.0 0.0 81 3 3 1.1 2.1 2.2 2.3 0.0 0.0 0.0 0.0 0.0 81 3 3 1.1 2.1 3.1 2.3 0.0 0.0 0.0 0.0 0.0 81 3 3 1.1 2.1 3.1 3.2 0.0 0.0 0.0 0.0 0.0 81 3 3 1.1 2.1 3.1 3.2 3.3 0.0 0.0 0.0 0.0 81
嗯…看到任何模式? :-)数据写入
data+((
1
*i)+j)*sizeof(lua_Number)
,而不是data+((
3
*i)+j)*sizeof(lua_Number)
(或任何矩阵的大小)。
再一次,你告诉编译器你有一个1×1数组。 (编译器并不关心你是在进行越界访问,事实上你可以写i[m->data][j]
而不是m->data[i][j]
你会得到完全相同的行为。)所以你不能让编译器为你做偏移计算,你必须手动完成。 声明一个二维数组只会妨碍,所以再次更改你的struct
typedef struct { int row; int col; LUA_NUMBER data[0]; } matrix;
( [0]
只是一个尾随变量大小的部分的约定。你可以说data[1]
,但这可能作为一个独立的struct
有意义struct
data[0]
什么都没有,哪个没有作为一个固定大小的struct
有意义 – 所以它相对清楚地传达(如果你知道这个约定),这应该是可变大小的。)
然后将所有出现的m->data[i][j]
更改为m->data[m->col*i + j]
。 (只是尝试编译,编译器会为你需要调整的行给出错误。)
最后的测试:
> m, size = lb.NewMatrix( 3, 3 ) > for i = 0, 2 do for j = 0, 2 do >> m:set( i, j, (i+1) + (j+1)/10 ) >> print( ("II"..("n "):rep(3*3)):unpack( m:peek( size ) ) ) >> end end 3 3 1.1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 81 3 3 1.1 1.2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 81 3 3 1.1 1.2 1.3 0.0 0.0 0.0 0.0 0.0 0.0 81 3 3 1.1 1.2 1.3 2.1 0.0 0.0 0.0 0.0 0.0 81 3 3 1.1 1.2 1.3 2.1 2.2 0.0 0.0 0.0 0.0 81 3 3 1.1 1.2 1.3 2.1 2.2 2.3 0.0 0.0 0.0 81 3 3 1.1 1.2 1.3 2.1 2.2 2.3 3.1 0.0 0.0 81 3 3 1.1 1.2 1.3 2.1 2.2 2.3 3.1 3.2 0.0 81 3 3 1.1 1.2 1.3 2.1 2.2 2.3 3.1 3.2 3.3 81
所以代码现在可以工作了。
测试任务的最后一个问题是您正在访问[1]
, [2]
, [3]
而不是[0]
, [1]
, [2]
。 C完全是关于偏移并使用从零开始的索引。 第一个元素位于[0]
而不是[1]
,最后一个元素位于[size-1]
而不是[size]
。 虽然你可以分配一个(n + 1)x(m + 1)矩阵然后可以使用1 … n和1 … m,这会浪费空间(3×3不多,但如果矩阵变大则越来越多)。 因此,将代码调整为C约定可能更好。
您还必须修改Lua可见访问function,它们目前允许越界访问。 ( data[3][3]
在3×3矩阵之外,“最外层”字段是data[2][2]
或data[m-1][n-1]
。)你必须决定你是否我想坚持基于Lua /索引的约定(从1开始,索引从1到n)或基于C /偏移的约定(从0开始,从0到(n-1)的偏移)。 (如果要将其用于矩阵数学,那么选择基于0的索引/偏移可能会更好,因为某些算法和公式可能会假设这一点而您可能不想全部更改它们。)
这个问题与Lua没有直接关系; 它主要是一个C问题。 简而言之,当temp->data
被动态分配时,你不能写temp->data[i][j]
,并希望它能工作,因为C编译器知道temp->data
是1×1矩阵。
要解决这个问题,首先要定义
typedef struct { int row; int col; LUA_NUMBER data[1]; }matrix;
data
是最后一个字段至关重要。
然后将矩阵中的位置i,j 线性地作为data[i*col + j]
。
以上就是c/c++开发分享Lua C API:在结构C中初始化变量矩阵相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/544771.html