本文讨论如何在lua中实现printf。学习的目的是为了进一步了解C函数和lua之间利用栈传值的过程。在lua中printf的功能等于string.format + io.wirte,前者用于格式化字符串,后者用于输出。文中的代码来自于lua官网。
用lua代码实现为:
printf= function(s, ...)
return io.write(s:format(...))
end
printf("%s\n", "Hello World!")
在C语言中实现为:
#include <Windows.h>
extern "C"{
#include <lua.h>
#include <lauxlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <lualib.h>
#include <math.h>
#include <limits.h>
}
static int l_printf (lua_State *L) {
lua_pushvalue(L, lua_upvalueindex(2)); //将format函数放置栈顶
lua_insert(L, 1); //将format函数插入至栈低,此时的栈内容为:string.format, arg1, arg2, ...
lua_call(L, lua_gettop(L) - 1, 1); //lua中的函数string.format和C语言中的printf是一样的,所以lua_gettop(L) - 1就是参数的个数。
//栈中只有:result
lua_pushvalue(L, lua_upvalueindex(1));//将write函数放置栈顶,栈中的内容为:result, io.write
lua_pushvalue(L, -2); //将io.write移到result之前,使result作为write的参数
lua_call(L, 1, 0); //调用write(result)
return 0;
}
int luaopen_printf (lua_State *L) {
lua_getglobal(L, "io");
lua_getglobal(L, "string");
lua_pushliteral(L, "write");//lua_upvalueindex(1)。等同于lua_pushstring,作用是将一个字符串放置于栈顶。
lua_gettable(L, -3); //-3是io在栈中的索引,在io table中查找key=write的项。如果找到,就将该项放入栈中,在放入之前删除之前压入的字符串"write"
lua_pushliteral(L, "format");//lua_upvalueindex(2)
lua_gettable(L, -3);
//将l_printf放置栈顶
lua_pushcclosure(L, l_printf, 2);//2表示为:在函数l_printf中,可以向上访问2个luaopen_printf栈中的值,即函数write和函数format。
//将栈顶元素(既l_printf)命名为printf,lua可以通过printf调用l_printf
lua_setglobal(L, "printf");
return 0;
}
int main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaopen_printf(L);
lua_pushstring(L, "lua is great!");
lua_setglobal(L, "lua"); //设置一个命名为lua的全局变量,其中的内容为字符串"lua is great!"
bool result = luaL_loadfile(L, "fordebug.lua");
if(!result) result = lua_pcall(L, 0, 0, 0);
lua_close(L);
system("pause");
return 0;
}
fordebug.lua中的代码:
printf("%s\n", lua) --> lua is great!