如何在使用Lua C函数时减少重复?

我有一段代码如下:

lua_newtable(L);

lua_pushstring(L, "gid");
lua_pushinteger(L, info[i].codepoint);
lua_settable(L, -3);
lua_pushstring(L, "cl");
lua_pushinteger(L, info[i].cluster);
lua_settable(L, -3);
lua_pushstring(L, "ax");
lua_pushnumber(L, pos[i].x_advance);
lua_settable(L, -3);
lua_pushstring(L, "ay");
lua_pushnumber(L, pos[i].y_advance);
lua_settable(L, -3);
lua_pushstring(L, "dx");
lua_pushnumber(L, pos[i].x_offset);
lua_settable(L, -3);
lua_pushstring(L, "dy");
lua_pushnumber(L, pos[i].y_offset);
lua_settable(L, -3);
lua_pushstring(L, "w");
lua_pushinteger(L, extents.width);
lua_settable(L, -3);
lua_pushstring(L, "h");
lua_pushinteger(L, extents.height);
lua_settable(L, -3);
lua_pushstring(L, "yb");
lua_pushinteger(L, extents.y_bearing);
lua_settable(L, -3);
lua_pushstring(L, "xb");
lua_pushinteger(L, extents.x_bearing);
lua_settable(L, -3);

我的操作只是在一个表格中设置一些字段,这些字段是字符串或数字。注意代码非常的重复。

有没有一种方式使其更加简洁,或者使用 C 宏来实现?

点赞
用户5622901
用户5622901

你可以通过将以下代码:

lua_pushstring(L, "cl");
lua_pushinteger(L, info[i].cluster);
lua_settable(L, -3);

替换为

lua_pushinteger(L, info[i].cluster);
lua_setfield(L, -2, "cl");

来减少其长度的三分之一等等。

2015-12-01 13:28:47
用户752976
用户752976

也许可以使用 C 宏?

更实用

使用 C11 通用宏,它变得更简单:

#define lua_push(L, X) _Generic((X), const char*: lua_pushstring, \
                                     float: lua_pushnumber, \
                                     int: lua_pushinteger)(L, X)

然后你可以将其封装在一个 lua_setfield_generic 中:

#define lua_setfield_generic(L, NAME, X) \
    lua_push(L, X); \
    lua_setfield(L, -2, NAME);

这是你的代码会是什么样子的:

lua_setfield_generic(L, "gid", info[i].codepoint);
lua_setfield_generic(L, "cl", info[i].codepoint);
lua_setfield_generic(L, "ax", pos[i].x_advance);

不那么实用,但很花里胡哨

由于你基本上是在将数据传递到 Lua 中,所以最好将其更加声明式和基于数据。

想象一下这样的 struct 定义:

STRUCT(Point)
FIELD(x, float);
FIELD(y, float);
END_STRUCT

通过巧妙的思考,你可以通过这个结构和一个函数 PointToLuaTable(为创建名称需要使用 ##)来建立一个结构,该函数将选择适当类型的 lua 函数并依次调用它们,从字段的名称中获取名称(通过 # 获得)。

你甚至可以进一步扩展它。制作自己的预处理器,使用 Clang 的 API 解析你的结构定义并生成适当的函数,然后作为第二个构建步骤使用这些文件来构建那些函数。

话虽这样——为什么你要在 C 中这样做?它不是一个专为此设计的语言。它缺乏反射和适当的泛型,不能使它有价值。

2015-12-01 13:35:13
用户3677376
用户3677376

你可以使用 C 预处理器将 C 宏应用于元组列表:

#define INFO_FIELDS( _ ) \
  _( codepoint, "gid", integer ) \
  _( cluster, "cl", integer )

#define POS_FIELDS( _ ) \
  _( x_advance, "ax", number ) \
  _( y_advance, "ay", number ) \
  _( x_offset, "dx", number ) \
  _( y_offset, "dy", number )

#define EXTENT_FIELDS( _ ) \
  _( width, "w", integer ) \
  _( height, "h", integer ) \
  _( y_bearing, "yb", integer ) \
  _( x_bearing, "xb", integer ) \

#define GEN( _m, _n, _t ) \
  (lua_push##_t( L, info[i]._m ), lua_setfield( L, -2, _n ));
INFO_FIELDS( GEN )
#undef GEN

#define GEN( _m, _n, _t ) \
  (lua_push##_t( L, pos[i]._m ), lua_setfield( L, -2, _n ));
POS_FIELDS( GEN )
#undef GEN

#define GEN( _m, _n, _t ) \
  (lua_push##_t( L, extents._m ), lua_setfield( L, -2, _n ));
EXTENT_FIELDS( GEN )
#undef GEN

我不确定在你的情况下是否值得,但是如果您可以多次使用这些列表(例如从堆栈中读取值并将其分配给结构字段,或首先定义 C 结构),则这将很有用。

2015-12-01 14:21:46