转自lua程序设计第二版
在Lua中,“数组”只是table的一个别名,像lua_settable和lua_gettable这种操作table的函数,也可以用于操作数组。
然而API为为数组操作提供了专门的函数。
* 出于性能考虑,通常会在算法中用循环来访问数组
* 为了方便,像字符串key,整数key是很常用的
//index表示在栈中的位置,key表示元素在 table中的位置
void lua_rawgeti(Lua_State *L,int index,int key);
void lua_rawseti(Lua_State *L,int index,int key);
//假设t为整数,
//lua_rawgeti(L,t,key)等价于
lua_pushnumber(L,key);
lua_rawget(L,t);
//lua_rawseti(L,t,key)等价于
lua_pushnumber(L,key);
lua_insert(L,-2);
lua_rawset(L,t);
int l_map(lua_State *L){
int i,n;
//第一个参数必须是table
luaL_checktype(L,1,LUA_TABLE);
//第二个参数必须是一个函数
lua_checktype(L,2,LUA_FUNCTION);
//获取table的大小
n = lua_objlen(L,1);
for(i = 1;i<=n;i++){
//压入f
lua_pushvalue(L,2);
//压入t[i]
lua_rawgeti(L,1,i);
//调用f(t[i])
lua_call(L,1,1);
//t[i] = 结果
lua_rawseti(L,1,i);
}
return 0;
}
当一个C函数从Lua收到一个字符串参数时,必须遵守两条规则:
* 不要再访问字符串时从栈中弹出它
* 不要修改字符串
//把一个字符串s的子串传递给Lua
//区间[i,j]
lua_pushlstring(L,s+i,j-i+1)
static int l_split(lua_State *L){
const char *s = luaL_checkstring(L,1);
const char *sep = luaL_chcekcstring(L,2);
const char *e ;
int i = 1;
//结果
lua_newtable(L);
//遍历所有分隔符
while((e = strchr(s,*sep)) != NULL){
//压入字符串
lua_pushlstring(L,s,e-s);
lua_rawseti(L,-2,i++);
//跳过分隔符
s=e+1;
}
//压入最后一个字符串
lua_pushstring(L,s);
lua_rawseti(L,-2,i);
//返回table
return 1;
}
//链接并弹出栈顶的n个值
void lua_concat (lua_State *L, int n);
类似于C函数sprintf.
但与sprintf不同的是,无需提供这个新字符串的缓冲。Lua会动态的创建一个足够大的缓存来存放新字符串。
* %% 字符%
* %s 字符串
* %d 整数
* %f 表示Lua中的数字,即双精度浮点数
* %c 接受一个整数,并将其格式化为一个字符
这套机制包含两个层面的缓冲
1. 类似于I/O操作中的缓冲,就是在一个本地缓冲中收集较小的字符串,并在本地缓冲填满后将结果传递给Lua(通过lua_pushlstring)
2. 使用lua_concat或其他栈算法来链接多次缓冲填满后的结果
//string.upper缓冲示例
static int str_upper(lua_State *L){
size_t l;
size_t i;
//声明一个luaL_Buffer变量
luaL_Buffer b;
const char* s = luaL_checklstr(L,1,&l);
//用luaL_buffinit来初始化,在初始化后,这个变量中会保留一份状态L的副本,由此再调用其他操作缓冲的函数时,就无需传递状态参数了。
luaL_buffinit(L,&b);
for(i = 0;i//将一个字符放入缓冲中
luaL_addchar(&b,toupper(unsigned char)(s[i])));
//将具有显式长度的字符串 luaL_addlstring
//将对于“0结尾”的字符串 luaL_addstring
}
//更新缓冲,并将最终的字符留在栈顶
lua_pushresult(&b);
return 1;
}
当向缓冲中添加东西时,缓冲会将一些中间结果放到栈中。因此,不应假设栈顶还是和使用缓冲之前一样。