编写C函数的技术-《lua程序设计》 27章 学习

1.数组操作

void lua_rawgeti(lua_State * L ,int index,int key)

void lua_rewseti(lua_State * L,int index,int key)

index表示table在栈的位置,key表示元素在table中的位置

test.lua内容

tab = {"a","b","c","c","e","f","g","h","i"}

function ShowTable(tabb)
    print("显示table")
    for k,v in pairs(tabb) do
        print(v .. ' ')
    end
end

ShowTable(tab)

print(GetTableFromIndex(tab,6))
SetTableFromIndex(tab,2,"aaaaaaaaaa")
ShowTable(tab)
static int GetTableFromIndex(lua_State * L )
{
    //GetTableFromIndex(tab,6)
    int index = luaL_checkint(L,2);
    lua_rawgeti(L,1,index);
    const char *  ret = luaL_checkstring(L,-1);
    return 1;
}
static int SetTableFromIndex(lua_State * L )
{
    //SetTableFromIndex(tab,2,"aaaaaaaaaa")
    int index = luaL_checkint(L,2);
    const char *  szNewValue = luaL_checkstring(L,3);
    lua_pushstring(L,szNewValue);
    lua_rawseti(L,1,index);
    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    lua_State * L = luaL_newstate();
    luaL_openlibs(L);
    lua_register(L,"GetTableFromIndex",GetTableFromIndex);
    lua_register(L,"SetTableFromIndex",SetTableFromIndex);
    if(0 != luaL_dofile(L,"test.lua"))
    {
        cout<<"error:"<<luaL_checkstring(L,-1)<<endl;
        lua_pop(L,1);
    }
    statckDump(L,"最后");
    lua_close(L);
    system("pause");
    return 0;
}

2.字符串操作

lua_pushlstring(L,s+I,j-i+1) 把一个字符串区间为[I,j]传递给lua

下面函数将一个字符串以分隔符生成一个表 例如调用 split(“he,3,66,22”) 会返回table {“he”,”3”,”66”,”22”}

test.lua

tableStrings = l_split("1111,2222,3333,4444,6666",",");
ShowTable(tableStrings)
static int l_split(lua_State * L )
{
    const char * s = luaL_checkstring(L,1);  //第一个参数要分隔的字符串
    const char * sep = luaL_checkstring(L,2);   //第二个参数分隔符
    const char * e;
    int i = 1;

    lua_newtable(L); //创建返回值 

    //遍历所有字符串分隔
    while((e = strstr(s,sep)) != NULL)
    {
        lua_pushlstring(L,s,e-s);  //压入子串
        lua_rawseti(L,-2,i++);     //修改table
        s = e + 1;  //跳过分隔符
    }
    //压入最后一个子串
    lua_pushstring(L,s);
    lua_rawseti(L,-2,i);
    return 1;
}

还有一些相关的函数 lua_pushfstring,luaL_buffinit,luaL_addchar,luaL_add 等lua帮助文件都有说明

3.在c函数中保存状态

对于一个lua函数 来说,有3种地方可以保存非局部数据他们是,全局变量,函数环境和非局部的变量(closure中)

3.1注册表

注册表是位于一个”伪索引“上,这个索引值由LUA_REGISTRYINDEX定义。伪索引就像一个栈中的索引,但它所关联的值不在栈中。为了获取注册表中的key为”Key”的值,可以这么做

lua_getfield(L,LUA_REGISTRYINDEX,”KEY”)

在注册表中为了避免冲突的key尽量不要用常用的名字,在注册表中不应使用数字类型的key,因为这种key是被”引用系统“所保留的,这个系统由辅助库中的一系列函数组成,它可以在向一个table存储value时忽略如何创建一个唯一 的key

int r = luaL_ref(L,LUA_REGISTRYINDEX);  //弹出一个值,然后用新分配的整数key来将这个值保存到注册表中,最后返回这个key,这个key被称为”引用 “

lua_rewgeti(L,LUA_REGISTRYINDEX,r); //将与引用关联的值压入栈中

luaL_unref(L,LUA_REGISTRYINDEX,r); //释放该值和引用

3.2 C函数环境

lua5.1开始每一个c函数都有自己的一个环境table一个函数可以像访问注册表一样通过一个伪索引来访问他的环境table环境table的伪索引是LUA_ENVIRONINDEX。在在C语言中设置环境的代码如下:

int luaopen_foo(lua_State * L)
{
    lua_newtable(L);
    lua_replace(L,LUA_ENVIRONINDEX);
    luaL_register(L,<库名>,<函数列表>);
    ...

}

3.3 upvalue

注册表提供了全局变量的存储,环境提供了模块变量的存储,而upvalue机制则实现了一种类似于c语言中静态变量的机制。这种变量只在一个特定函数中可见。每当lua中创建一个函数时,都可以瘵任务数量的upvalue与这个函数关联

将这种c函数与upvalue关联称为closureg一个c closure类似于Lua closure。closure可以用同一个函数代码来创建多个closure,每个closre可以拥有不同的upvalue

 

static int counter(lua_State * L)
{
    int val = lua_tointeger(L,lua_upvalueindex(1));  //luaj_upvalueindex可以生成一个upvalue的伪索引,注意这个索引可以像其它栈索引一样,但不存在于栈中
    lua_pushinteger(L,++val);
    lua_pushvalue(L,-1);
    lua_replace(L,lua_upvalueindex(1)); //更新updavalue
    return 1;
}
int newCounter_(lua_State * L)
{
    lua_pushinteger(L,0);  //创建cclosure前必须将cclosure初始值压栈
    lua_pushcclosure(L, //创建一个cclosure
        &counter, //基础函数
        1);  //upvalue个数
    return 1;
}
时间: 2024-09-17 23:35:57

编写C函数的技术-《lua程序设计》 27章 学习的相关文章

Lua教程(二十一):编写C函数的技巧_Lua

1. 数组操作:     在Lua中,"数组"只是table的一个别名,是指以一种特殊的方法来使用table.出于性能原因,Lua的C API为数组操作提供了专门的函数,如:   复制代码 代码如下:     void lua_rawgeti(lua_State* L, int index, int key);     void lua_rawseti(lua_State* L, int index, int key);       以上两个函数分别用于读取和设置数组中的元素值.其中i

JavaScript教程:编写匿名函数的几种方法

匿名函数可以有效控制变量作用域,构造闭包 (Closure),防止对全局变量造成污染.在 JavaScript 中,编写匿名函数,有以下几种方法: 错误模式:语法错误警告 function(){ // insert code here }(); 模式一:函数字面量 (Function Literal) 先声明函数对象,然后执行. (function(){ // insert code here })(); 模式二:优先表达式 (Prior Expression) 由于 JavaScript 按照

c++-编写一个函数,对输入的整数k输出它的全部素数因子。……格式为126=2*3*3*7

问题描述 编写一个函数,对输入的整数k输出它的全部素数因子.--格式为126=2*3*3*7 解决方案 不知道你的编译器是什么,如果只是输出格式不对,就加一句: #include"iostream" using namespace std; #include<math.h> void main() { int x,i; cout<<"输入整数:"; cin>>x; cout<<x<<"="

c++ 指针-一个c++指针的问题,要求编写一个函数

问题描述 一个c++指针的问题,要求编写一个函数 有这样一个题,要求编写一个函数,以char指针数组和数组中的指针数量作为参数,返回最长字符串的地址.我想请问这个函数的返回值的类型是什么呢?也就是说在声明函数时函数类型应该是char *** 还是其他呢?因为我认为 **char *** 指的是返回一个指向单个字符的指针而不是指向字符串的指针,而且这个函数怎么编写呢?以下是我写的源代码,虽然通过了编译,但是在运行时崩溃了 ** **char* maxn( char *** arr[],int le

js使用函数绑定技术改变事件处理程序的作用域_javascript技巧

第一种,也是 最常见的,就是直接在html标签里面通过指定事件处理程序同名的HTML属性来注册事件,代码如下: 复制代码 代码如下: function eventHandler() { alert("当前作用域是 input 元素本身"); } <input type="button" value="单击我" onclick="eventHandler(this)"/> 第二种方式就是将一个函数赋值给一个事件处理程

c语言-求教编写一个函数求出两个字符串包含的相同的单词

问题描述 求教编写一个函数求出两个字符串包含的相同的单词 编写一个函数,函数首部为void maxword(char *s,char *t),求出两个字符串包含的相同单词(同一字母的大小写视为不同的字符).规定单词全部由英文字母构成,单词直接由一个或多个空格分隔.其中主函数如下: #include Void main() { Char s[]="This is C programming text"; Char t[]="This is a text for C progra

十进制数-用vcmfc编写一个函数 在发送按钮事件下调用这个函数 具体见正文

问题描述 用vcmfc编写一个函数 在发送按钮事件下调用这个函数 具体见正文 该函数需将BYTE编辑框变量十进制数转化为16进制数,在按钮事件下调用该函数 进行转化.我是新手 求指导 刚接触vc思维上有点转不过来 解决方案 大概的思路char * input= ""00FF0123D5..."";char* out2=new char[strlen(input/2];int count=0;for(char *s=input;strlen(s)>0;s+=2)

编写一个函数,转换十进制数为字符串,需要处理负数,为什么会有错误呢

问题描述 编写一个函数,转换十进制数为字符串,需要处理负数,为什么会有错误呢 /* 编写一个函数,转换字符串的逆序字符串,比如"ABC"转换为"CBA".*/void reverse(char r[]int n){ int i; int temp; for(i=0;i<n/2;i++) { temp=r[i]; r[i]=r[n-i-1]; r[n-i-1]=temp; }}void chang1(int a){ int i = 0 j = 0 temp =

Viusla Basic 6..0 语言编写一个函数,把uncode字符串转换为utf-8字符串

问题描述 Viusla Basic 6..0 语言编写一个函数,把uncode字符串转换为utf-8字符串 Viusla Basic 6..0 语言编写一个函数,把uncode字符串转换为utf-8字符串 解决方案 dim e as object Set?e=CreateObject("MSScriptControl.ScriptControl") e.Language?=?"javascript" dim d as stringd=?e.Eval("en