当在userdata上调用__len元方法时,Lua向C传递两个参数,分别是nil和userdata。那么nil参数是用来做什么的呢?

这是一个小的 C 测试程序,用来演示我看到了什么。它注册了一个新的 Lua 对象类型并执行一个 Lua 脚本。当脚本调用 __len 元方法时,我期望只有一个参数会被传递到堆栈上 - 对象的 userdata。然而它传递了 userdata 和一个神秘的 nil。

len.c:

包括 <stdio.h>
#include <lua5.1/lua.h>
#include <lua5.1/lauxlib.h>
#include <lua5.1/lualib.h>

#define OBJECT_LEN 123456

/* 虚拟的对象 */
typedef struct {
    int length;
} object;

/* 创建新对象并将对象长度设置为 OBJECT_LEN */
static int object_new( lua_State *L ) {
    object *new = lua_newuserdata( L, sizeof( object ) );
    new->length = OBJECT_LEN;
    luaL_getmetatable( L, "metatable" );
    lua_setmetatable( L, 1 );
    return 1;
}

/* 获取对象的长度 */
static int object_len( lua_State *L ) {
    /* 打印 Lua 的堆栈 - 总是有 2 个参数,userdata 和 nil */
    static const char *const lua_types[] = {
        "nil", "boolean", "light userdata", "number", "string",
        "table", "function", "userdata", "thread",
    };
    int arg_count = lua_gettop( L );
    int i;
    for ( i = arg_count; i > 0; -- i ) {
        int type = lua_type( L, i );
        printf( "%d:%s\n", i, lua_types[ type ] );
    }

    /* 将对象的长度推入 Lua 的堆栈 */
    object *obj = luaL_checkudata( L, 1, "metatable" );
    lua_pop( L, 2 ); /* 弹出神秘的 'nil' 和 userdata */
    lua_pushinteger( L, obj->length );

    return 1;
}

static const luaL_reg object_constructor[] = {
    { "new", object_new },
    { NULL, NULL }
};

static const luaL_reg object_methods[] = {
    { "__len", object_len },
    { NULL, NULL }
};

int main( int argc, char **argv ) {
    lua_State *L = lua_open();
    luaL_openlibs( L );

    /* 创建 'object' 类型 */
    luaL_newmetatable( L, "metatable" );
    lua_pushvalue( L, -1 );
    lua_setfield( L, -2, "__index" );
    luaL_register( L, NULL, object_methods );
    luaL_register( L, "object", object_constructor );
    lua_pop( L, 2 );

    /* 运行 Lua 脚本 */
    int result = luaL_dofile( L, "meta.lua" );
    if ( result != 0 ) {
        fprintf( stderr, "error:%s\n", lua_tostring( L, 1 ) );
    }

    lua_close( L );

    return 0;
}

meta.lua: 创建一个对象并打印它的长度。

obj = object.new()
print( "obj length:", #obj )

编译并执行:

$ gcc -Wall len.c -o len -llua5.1 && ./len
2:nil
1:userdata
obj length:     123456

为什么堆栈上有一个 nil?

原文链接 https://stackoverflow.com/questions/4911112

点赞
stackoverflow用户33252
stackoverflow用户33252

这是一个“不重要的实现细节”。

请参见 这个 lua-l 信息线程

2011-02-06 03:12:38