Lua Printf

lua-users home
wiki

本页面演示了如何在 Lua 中部分模拟 C printf 字符串格式化函数。

在 Lua 中

使用 io.write()print()string.format() 在 Lua 中编写格式化文本很容易。io.writeprint 类似,只是 io.write 不会在每个输出后添加换行符。C 函数 printf() 可以模拟为

> io.write(string.format("Hello from %s on %s\n",_VERSION,os.date()))
Hello from Lua 5.1 on Mon Jan  1 22:11:56 2007

或者,可以将其封装在一个函数中,如下所示:

printf = function(s,...)
           return io.write(s:format(...))
         end -- function

然后可以像这样使用:

printf("Hello from %s on %s\n",_VERSION,date())

在上面的示例中,printf() 的格式字符串和可变参数列表被传递给 string.format()write() 打印生成的格式化字符串。[*1]

有趣的是,Lua 5.1 中字符串方法的语法强制对第一个参数进行单独处理。这是有道理的,因为它与其他参数的作用完全不同。

请注意,Lua 的 string.format 函数不支持完整的 C 格式规范 [1],因此此函数不能直接替换。如果您需要 C 格式规范的全部功能,您可能需要在 C 代码中执行 printf 调用,然后从 Lua 中调用它。或者,您可以使用 C 字符串函数在 Lua 中完全模拟您需要的行为(更多工作量)。

在 C 中

上面的示例可以用 C 代码编写如下。这还通过捕获两个标准库函数作为上值来进行优化,而不是每次都查找它们(尽管每次都查找它们具有更动态的优势)。不过,您可能只想使用 Lua 版本。

static int l_printf (lua_State *L) {
  lua_pushvalue(L, lua_upvalueindex(2));
  lua_insert(L, 1);
  lua_call(L, lua_gettop(L) - 1, 1);
  lua_pushvalue(L, lua_upvalueindex(1));
  lua_pushvalue(L, -2);
  lua_call(L, 1, 0);
  return 0;
}

int luaopen_printf (lua_State *L) {
  lua_getglobal(L, "io");
  lua_getglobal(L, "string");
  lua_pushliteral(L, "write");
  lua_gettable(L, -3);
  lua_pushliteral(L, "format");
  lua_gettable(L, -3);
  lua_pushcclosure(L, l_printf, 2);
  /* With 5.1, I'd probably just return 1 at this point */
  lua_setglobal(L, "printf");
  return 0;
}

一个 C 函数 l_printf 在 Lua 中注册为 printf。当从 Lua 调用 l_printf 时,format() 会使用给定的参数调用,然后 write() 会使用 format 的结果调用,最后返回结果的数量。


-- 感谢 lhf 提供的示例。

脚注

[*1] Lua 4 版本为

function printf(...)
  write(call(format,arg))
end

static int l_printf (lua_State *l)
{
    lua_getglobal(L,"format");
    lua_insert(L,1);
    lua_call(L,lua_gettop(L)-1,LUA_MULTRET);
    lua_getglobal(L,"write");
    lua_insert(L,1);
    lua_call(L,lua_gettop(L)-1,LUA_MULTRET);
    return lua_gettop(L);
}

lua_register(L,"printf",l_printf);


-- Sirmabus: 2009年9月13日 - 上述 Lua 代码的一个改进是使用 pcall() 包装器来捕获错误并指向有问题的 printf()。否则很难确切地知道错误来自哪里。

function printf(...)
   local function wrapper(...) io.write(string.format(...)) end
   local status, result = pcall(wrapper, ...)
   if not status then error(result, 2) end
end

最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2009年9月14日凌晨1:13 GMT (差异)