• C与Lua互相调用的时候,栈变化分析


                                                                              1  C调用Lua函数的堆栈变化

    例子

    Lua文件中的函数
     function testNewCounter2()
    
     return "第四个结果"
    
    end 
    
    C中的例子
    void t_new(lua_State *aaa){
    
     }
    
    
         lua_pushstring(aaa, "feifei");
    
         lua_pushcfunction(aaa, t_new);
         const char *ccc= lua_tostring(aaa, -2);
    
         printf("倒数第二个的值为%s
    ",ccc);
    
         lua_getglobal(aaa, "testNewCounter2");
    
         int iiiiif=lua_gettop(aaa);
    
         printf("现在栈内得数目=%d
    ",iiiiif);
    
         lua_pcall(aaa, 0, 1, 0);
    
        int iiiii=lua_gettop(aaa);
    
        printf("执行函数之后现在栈内得数目=%d
    ",iiiii);
    
        const char *ccfffc= lua_tostring(aaa, -3);//倒数第三个
    
        const char *ccfffc2= lua_tostring(aaa, -1);//倒数第一个,也就是lua函数的返回值
    
         printf("倒数第三个=%s
    ",ccfffc);
    
         printf("倒数第一个,也就是lua函数的返回值=%s
    ",ccfffc2);

    运行结果如下:

    倒数第二个的值为feifei

    现在栈内得数目=3

    执行函数之后现在栈内得数目=3

    倒数第三个=feifei

    倒数第一个,也就是lua函数的返回值=第四个结果

    也就是说函数执行完了之后,首先是把自身弹出,然后把返回结果压住栈内,

    而在函数压入之前的,比如feifei等,函数控制不了,也不会把他们弹出

     下面给lua函数加一个参数试试,也就是lua文件的函数为

    function testNewCounter2(para)
    
     return "第四个结果” .. para
    
    end 
    
     lua_pushstring(aaa, "feifei");
    
         lua_pushcfunction(aaa, t_new);
    
         const char *ccc= lua_tostring(aaa, -2);
    
         printf("倒数第二个的值为%s
    ",ccc);
    
         lua_getglobal(aaa, "testNewCounter2");
    
         lua_pushstring(aaa, "lua的参数");
    
         int iiiiif=lua_gettop(aaa);
    
         printf("现在栈内得数目=%d
    ",iiiiif);
    
         lua_pcall(aaa, 1, 1, 0);
    
        int iiiii=lua_gettop(aaa);
    
        printf("执行函数之后现在栈内得数目=%d
    ",iiiii);
    
        const char *ccfffc= lua_tostring(aaa, -3);//倒数第三个
    
        const char *ccfffc2= lua_tostring(aaa, -1);//倒数第一个,也就是lua函数的返回值
    
         printf("倒数第三个=%s
    ",ccfffc);
    
         printf("倒数第一个,也就是lua函数的返回值=%s
    ",ccfffc2);

    返回结果:
    倒数第二个的值为feifei

    现在栈内得数目=4

    执行函数之后现在栈内得数目=3

    倒数第三个=feifei

    倒数第一个,也就是lua函数的返回值=第四个结果lua的参数

    和预期的一样,lua函数在执行完之后,会吧他自身和他的参数弹出,然后把返回结果压入栈中

           

                                                              2  Lua调用C函数的堆栈变化

    首先lua文件中函数为
    
       
        function testNewCounter2(para)
            ccc=new222()
         end
    
    c文件中的函数
    int t_new(lua_State *aaa){
    
        int ffdsfdsf=lua_gettop(aaa );
    
        printf("函数私有栈的数目=%d
    ",ffdsfdsf);
    
        lua_pushstring(aaa, "C函数的结果");
    
        int ffdsfdsffds=lua_gettop(aaa);
    
        printf("加入一个结果之后的函数私有栈的数目=%d
    ",ffdsfdsffds);
    
        return 1;
    
    }

    备注:这里需要说明的一点是返回值为1,说明就一个返回结果,表示压入栈中的返回值数量。因此这个函数无需在压住结果之前清空栈,在他返回后,Lua会自动删除栈中结果之下的内容,就是说不管你加入几个元素进栈,只看返回结果,返回结果是几,就把几个加入到全局栈,其余的会清空,在函数返回完毕之后,函数内的私有栈也全部清空,在最后一步return数目的时候,确实是加入到了全局栈,而函数开始的时候,获取的参数第一个始终是传过来的参数,而不是全局栈中最顶上一个元素,这一点要区分开

    调用代码如下:

     lua_pushstring(aaa, "feifei");
    
               lua_pushstring(aaa, "wenqian");
    
            lua_pushcfunction(aaa, t_new);
    
            lua_setglobal(aaa, "new222");
    
            lua_getglobal(aaa, "testNewCounter2");
    
            lua_pcall(aaa, 0, 0, 0);
    
    
    
            const char *ccc= lua_tostring(aaa, -1);
    
            printf("执行完函数之后倒数第一个=%s
    ",ccc);
    
            const char *ccc2= lua_tostring(aaa, -2);
    
            printf("执行完函数之后倒数第二个=%s
    ",ccc);

    结果:
    函数私有栈的数目=0

    加入一个结果之后的函数私有栈的数目=1

    执行完函数之后倒数第一个=wenqian

    执行完函数之后倒数第二个=feifei

    首先来看 t_new函数里面有一个私有栈,不受外部影响,他的栈里面就是传给他的参数。

    然后看调用代码,第一和第二是加入两个字符串,然后注册t_new,然后调用

    testNewcounter2,调用玩之后,栈弹出这个函数,因为函数没有返回值,所以此时栈内有两个,就是开始加入的两个字符串。

    下面再看看让testNewCounter2返回结果时候的调用

    这里只是修改lua文件中的方法,改为:
        function testNewCounter2( )
    
        ccc=new222()
    
         return "返回new222的结果" .. ccc
    
        end
    开始调用
          lua_pushstring(aaa, "feifei");
    
            lua_pushstring(aaa, "wenqian");
    
            lua_pushcfunction(aaa, t_new);
    
            lua_setglobal(aaa, "new222");
    
            lua_getglobal(aaa, "testNewCounter2");
    
            lua_pcall(aaa, 0, 1, 0);
    
    
    
            const char *ccc= lua_tostring(aaa, -1);
    
            printf("执行完函数之后倒数第一个=%s
    ",ccc);
    
            const char *ccc2= lua_tostring(aaa, -2);
    
            printf("执行完函数之后倒数第二个=%s
    ",ccc2);

    结果:
    函数私有栈的数目=0

    加入一个结果之后的函数私有栈的数目=1

    执行完函数之后倒数第一个=返回new222的结果C函数的结果

    执行完函数之后倒数第二个=wenqian

    倒数第一个成了new222返回的结果,和预期的一样

    Lua和c的交互中还有一个比较难理解的地方就是upvalue。upvalue实现了一种类似于C语言中静态变量的机制,这种变量只在一个特定的函数中可见。每当在Lua中创建一个函数时,都可以将任意数量的upvalue与这个函数相关联。每个upvalue都可以保存一个lua值。以后,在调用这个函数时,就可以通过伪索引来访问这些upvalue了
    closure可以用一个函数代码来创建多个closure,每个closure可以拥有不同的upvalue。

    下面得例子,在c语言中创建一个newCounter函数。这个函数是一个工厂函数,每次调用都返回一个新的账户函数

    int newCounter(lua_State *aaa){
    
         lua_pushinteger(aaa, 0);
    
         lua_pushcclosure(aaa, &counter, 1);
    
         int fff=lua_gettop(aaa);
    
        printf("推入了closure之后,站内的数量=%d",fff);
    
        return 1;
    
    }
    
    static int counter(lua_State *aaa){
    
       int val=(int)lua_tointeger(aaa, lua_upvalueindex(1));
    
       int fdsfdsf= lua_gettop(aaa);
    
        printf("每次进入时栈的数量=%d",fdsfdsf);
    
        lua_pushinteger(aaa, ++val);
    
        lua_pushvalue(aaa, -1);
    
        lua_replace(aaa, lua_upvalueindex(1));
    
         int fdsfdsf11fds1= (int)lua_gettop(aaa);
    
        printf("最后栈的数量=%d",fdsfdsf);
    
         return 1;
    
    }
    
    在Lua文件中,函数如下:
    function newCounterFactory()
    
      counterFun=newCounter();
    
     return counterFun()
    
    end
    
    
    
    function newCounterFactoryAgain()
    
     return counterFun()
    
    end
    
    C语言调用代码如下:
                lua_pushstring(aaa, "feifei");
    
                lua_pushstring(aaa, "wenqian");
    
                lua_pushcfunction(aaa, newCounter);
    
                lua_setglobal(aaa, "newCounter");
    
                lua_getglobal(aaa, "newCounterFactory");
    
                lua_pcall(aaa, 0, 1, 0);
    
    
    
                const char *ccc= lua_tostring(aaa, -1);
    
                printf("第一次调用倒数第一个值=%s
    ",ccc);
    
                const char *ccc22= lua_tostring(aaa, -2);
    
                printf("第一次调用倒数第二个值=%s
    ",ccc22);
    
               lua_getglobal(aaa, "newCounterFactoryAgain");
    
               lua_pcall(aaa, 0, 1, 0);
    
        
    
              const char *ccccc= lua_tostring(aaa, -1);
    
              printf("第二次调用倒数第一个值=%s
    ",ccccc);
    
              const char *ccccc2= lua_tostring(aaa, -2);
    
              printf("第二次调用倒数第二个值=%s
    ",ccccc2);
    
             const char *ccccc3= lua_tostring(aaa, -3);
    
            printf("第二次调用倒数第三个值=%s
    ",ccccc3);

    运行结果:
    推入了closure之后,站内的数量=1

    每次进入时栈的数量=0

    最后栈的数量=1

    第一次调用倒数第一个值=1

    第一次调用倒数第二个值=wenqian

    每次进入时栈的数量=0

    最后栈的数量=1

    第二次调用倒数第一个值=2

    第二次调用倒数第二个值=1

    第二次调用倒数第三个值=wenqian


    从第二次调用可以看出,每一次counter()调用完了之后,确实是加入到了全局栈

    现在分析 一下特殊情况

    第一:修改一下lua函数,让newCounterFactory只是返回counter函数,而不执行,如下:
    
    function newCounterFactory()
      counterFun=newCounter();
      return counterFun
    end
    执行代码如下:
       lua_pushstring(aaa, "feifei");
                lua_pushstring(aaa, "wenqian");
    
                lua_pushcfunction(aaa, newCounter);
                lua_setglobal(aaa, "newCounter");
                lua_getglobal(aaa, "newCounterFactory");
                lua_pcall(aaa, 0,1, 0);
        
       
               auto ffdsfdsfdsfdsfff=lua_isfunction(aaa, -1);
               printf("是不是函数:%d
    ",ffdsfdsfdsfdsfff);
               // lua_pcall(aaa, 0,1, 0);
        
                const char *ccc= lua_tostring(aaa, -1);
                printf("第一次调用倒数第一个值=%s
    ",ccc);
                const char *ccc22= lua_tostring(aaa, -2);
                printf("第一次调用倒数第二个值=%s
    ",ccc22);
               const char *ccc22222= lua_tostring(aaa, -3);
               printf("第一次调用倒数第二个值=%s
    ",ccc22222);

    运行结果:
    推入了closure之后,站内的数量=1
    是不是函数:1
    第一次调用倒数第一个值=(null)
    第一次调用倒数第二个值=wenqian
    第一次调用倒数第二个值=feifei

    分析得知,newCounter没有执行,因为newCounterFactory()只是返回了他,并把它加入了全局栈中,所以全局栈中第一个是
    function。

    那么我们现在我们知道现在newCounter函数是位于全局栈的顶部,那么我们可以执行一下他,调用代码如下:
     lua_pushstring(aaa, "feifei");
                lua_pushstring(aaa, "wenqian");
    
                lua_pushcfunction(aaa, newCounter);
                lua_setglobal(aaa, "newCounter");
                lua_getglobal(aaa, "newCounterFactory");
                lua_pcall(aaa, 0,1, 0);
        
       
               auto ffdsfdsfdsfdsfff=lua_isfunction(aaa, -1);
               printf("是不是函数:%d
    ",ffdsfdsfdsfdsfff);
              —-执行以下栈顶函数
               lua_pcall(aaa, 0,1, 0);
        
                const char *ccc= lua_tostring(aaa, -1);
                printf("第一次调用倒数第一个值=%s
    ",ccc);
                const char *ccc22= lua_tostring(aaa, -2);
                printf("第一次调用倒数第二个值=%s
    ",ccc22);
               const char *ccc22222= lua_tostring(aaa, -3);
               printf("第一次调用倒数第二个值=%s
    ",ccc22222);

    运行结果如下:
    推入了closure之后,站内的数量=1
    是不是函数:1
    每次进入时栈的数量=0
    最后栈的数量=1
    第一次调用倒数第一个值=1
    第一次调用倒数第二个值=wenqian
    第一次调用倒数第二个值=feifei

    newCounter函数执行完毕,把他的参数和他自己出栈,然后压入他的返回值

    那么返过来再看看最初的执行情况,就是newCounterFactory函数里面直接执行newCounter,这里在运行一遍结果
    首先改一下lua代码
    function newCounterFactory()
      counterFun=newCounter();
     -- return counterFun
     return counterFun()
    end
    调用代码如下:
        lua_pushstring(aaa, "feifei");
                lua_pushstring(aaa, "wenqian");
    
                lua_pushcfunction(aaa, newCounter);
                lua_setglobal(aaa, "newCounter");
                lua_getglobal(aaa, "newCounterFactory");
                lua_pcall(aaa, 0,1, 0);
        
       
               auto ffdsfdsfdsfdsfff=lua_isfunction(aaa, -1);
               printf("是不是函数:%d
    ",ffdsfdsfdsfdsfff);
        
        
                const char *ccc= lua_tostring(aaa, -1);
                printf("第一次调用倒数第一个值=%s
    ",ccc);
                const char *ccc22= lua_tostring(aaa, -2);
                printf("第一次调用倒数第二个值=%s
    ",ccc22);
               const char *ccc22222= lua_tostring(aaa, -3);
               printf("第一次调用倒数第二个值=%s
    ",ccc22222);
    
    运行结果:
    
    推入了closure之后,站内的数量=1
    每次进入时栈的数量=0
    最后栈的数量=1
    是不是函数:0
    第一次调用倒数第一个值=1
    第一次调用倒数第二个值=wenqian
    第一次调用倒数第二个值=feifei

    和上个例子是一样得,只不过前者是在C里面执行了newCounter,而后者是在lua里面执行的,我认为他们都是一样的,虽然执行完了这个函数就出栈了,
    在C语言中无法再次执行了,但是因为在lua中保存了他的一个引用【在哪里引用的?当newCounter执行过程中,lua_pushcclosure讲一个新的
    closure留在了栈上,并以此作为newCounter的返回值,而在lua中的全局变量counterFun引用了他的返回值】,所以依然可以再次调用。

    下面再看最后一种情况,验证函数里面加入栈的元素,到底对全局栈有什么影响

    lua函数如下:
    function newCounterFactory()
      counterFun=newCounter();
      return counterFun
     --return counterFun()
    end
    C中newCounter方法
    int newCounter(lua_State *aaa){
       
       
          lua_pushstring(aaa, "001");
          lua_pushstring(aaa, "002");
          lua_pushinteger(aaa, 0);
          lua_pushcclosure(aaa, &counter, 1);
         int fff=lua_gettop(aaa);
        printf("推入了closure之后,站内的数量=%d
    ",fff);
        return 1;
    }
    在这里,我们多推入了几个元素,但是还是返回一个
    调用代码如下:
    lua_pushstring(aaa, "feifei");
                lua_pushstring(aaa, "wenqian");
    
                lua_pushcfunction(aaa, newCounter);
                lua_setglobal(aaa, "newCounter");
                lua_getglobal(aaa, "newCounterFactory");
                lua_pcall(aaa, 0,1, 0);
        
       
                auto ffdsfdsfdsfdsfff=lua_isfunction(aaa, -1);
                printf("是不是函数:%d
    ",ffdsfdsfdsfdsfff);
        
        
                const char *ccc= lua_tostring(aaa, -1);
                printf("第一次调用倒数第一个值=%s
    ",ccc);
                const char *ccc22= lua_tostring(aaa, -2);
                printf("第一次调用倒数第二个值=%s
    ",ccc22);
               const char *ccc22222= lua_tostring(aaa, -3);
               printf("第一次调用倒数第二个值=%s
    ",ccc22222);

    运行结果:
    推入了closure之后,站内的数量=3
    是不是函数:1
    第一次调用倒数第一个值=(null)
    第一次调用倒数第二个值=wenqian
    第一次调用倒数第二个值=feifei

    可以看到函数内入栈数目取决于返回值,返回值是几,就入栈几个,加到之前全局栈里面元素的上面,函数内其余的元素都会清除,而函数本身的私有栈也是全部清空了,
    通过每次运行函数,在里面调用lua_gettop可以看得出来,私有栈不受全局栈影响,他的第一个参数永远是传入方法的第一个参数,而不是全局栈顶部的元素

     

  • 相关阅读:
    自动生成A~Z的按字母查询可以用到(不用一一去写A.B.C……Z)
    GridView导出Excel
    简单的遮罩层弹出框(弹出一个表单,里面包含验证码,验证码正确方可提交)
    根据IP地址返回IP的详细信息(Web Service)
    九方格游戏的代码(此逻辑算法适用于任意方格数)
    for循环的变量设置
    注意TextField文本宽高
    两个重叠显示对象的层级调整(第二种方法时候来补充的
    用数组来存储显示对象
    DisplayObjectContainer的getChildAt()方法
  • 原文地址:https://www.cnblogs.com/xiaonanxia/p/4978021.html
Copyright © 2020-2023  润新知