自定义函数参数传递问题

文章讨论了一个在解释程序中遇到的bug,涉及函数调用时参数自右向左传递的问题。bug源于固定位置的参数被后续嵌套函数的参数覆盖,解决方法是使用动态内存分配。作者反思了代码设计中的不合理之处和可能的优化方向。
摘要由CSDN通过智能技术生成

最近,被一个函数调用参数传递的问题困惑了一阵。自己写的解释程序,一直用的好好的。在暗自得意的过程中,突然出现了bug,被泼了一头冷水。当然,bug是在无意中被发现的,确定以后则可以编制专用的代码来揭示它:

func showargs(a, b, c)
{
	    print a, b, c;
		return c+1;
}

showargs(1,2,3);
1 2 3
showargs(showargs(1,2,3),showargs(4,5,6),100);
4 5 6
1 2 3
4 2 3

参数是自右向左传递的。但最后一个print打印的结果不对。最后一个print打印当然应该是[4 7 100]。不是自定义函数代码写错,而是解释程序暴露了bug。


struct exprval e_fcall(int fi, struct node *paras, int *exception)
{
        struct funxat *f;
        struct node *p;
        struct exprval e;
        int i;
        struct exprval ret;

        f = &userfunc[fi];
        p = paras;
        i=0;
        while(p) {
                p = p->left;
                ++i;
        }
        if (i != f->paras) {
                printf("function %s(...) need %d paras, but given %d\n",
                        f->name, f->paras, i);
                *exception =1; goto exception_out;
        }

        p = paras;
        for(i=f->paras-1; i>=0; --i) {
                e = e_eval(p->right, exception); EXCEPTION_CHK;
                symtab_compile[DM_FOR_LOCAL].var[i]= e;
                p= p->left;
        }

        if (f->loop == f->warning) {
                printf("waring: func %s(...) nest called in %d levels\n",
                        f->name, f->loop);
                f->warning = terminate_loop -(terminate_loop -f->warning)/4;
        }

        if (f->loop >terminate_loop) {
                printf("exception: func %s(", f->name);
                for(i=0; i<f->paras; i++) {
                        if(i>0) printf(",");
                        e =symtab_compile[DM_FOR_LOCAL].var[i];
                        if (e.type==0) {
                                printf("~%d", e.u.value);
                        }
                        else {
                                printf("~%lf", e.u.d_value);
                        }
                }
                printf(") is terminated!;\n");
                *exception =1;
                goto exception_out;
        }

        f->loop++;

        alloc_context(f);
        for(i=0; i<f->paras; i++) {
                stk->e[top].bp[i] =symtab_compile[DM_FOR_LOCAL].var[i];
        }

        execute_e_ls(f->syntree, 0, exception); //.. ..............
        ret = stk->e[top].ret;
        free_context();
        f->loop--;
        if (f->loop==0) {
                f->warning= terminate_loop - (terminate_loop/4);
        }

exception_out:
        if (*exception==1) {
        }
        return ret;
}

这是解释程序相关部分的代码。问题就在

        for(i=f->paras-1; i>=0; --i) {
                e = e_eval(p->right, exception); EXCEPTION_CHK;
                symtab_compile[DM_FOR_LOCAL].var[i]= e;
                p= p->left;
        }

这个语句。symtab_compile[DM_FOR_LOCAL].var[i]= e; 这个用法是导致出现bug的根本原因。由于固定位置重入,传入的参数,被后来嵌套的函数的参数传递覆盖了。当时这样用是因为,程序在执行期间, symtab_compile[DM_FOR_LOCAL].var[]作为为编译配置的内存资源,被闲置着。记得当时隐约觉得这样写有些不妥,但稍微细想一下又没发现问题。终于抵制不住诱惑,挪用了配置给编译期的内存。正解当然是动态分配一个f->paras个数的mixtype数组来存放参数,最后在函数返回时候释放它。遇到嵌套的函数时因为会重新一个这样的分配,就不会出现重入的问题,不会发生参数覆盖,这样就解决问题了。

修复的代码就不展示了。因为,个人还不死心,仍然想利用这个闲置的编译期的内存。当然,改动会变得复杂,还会有更多的坑需要去踩… …

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值