自定义函数参数传递问题

最近,被一个函数调用参数传递的问题困惑了一阵。自己写的解释程序,一直用的好好的。在暗自得意的过程中,突然出现了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数组来存放参数,最后在函数返回时候释放它。遇到嵌套的函数时因为会重新一个这样的分配,就不会出现重入的问题,不会发生参数覆盖,这样就解决问题了。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/210031.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

重积分的应用@物体对外部质点的引力问题

文章目录 引力(*)分析两质点间的引力公式三重积分计算引力薄片情形计算例 引力(*) 这里讨论的是:空间一物体对于物体外一点 P 0 ( x 0 , y 0 , z 0 ) P_{0}(x_0,y_0,z_0) P0​(x0​,y0​,z0​)处单位质量的质点的引力 分析 仍然使用元素法, 设占有空间有界闭区域 Ω \Omega …

网络协议与 IP 编址

网络协议与 IP 编址 之前大概了解过了网络的一些基础概念&#xff0c;见文章&#xff1a; 网络基础概念。 之前简单了解OSI模型分层&#xff1a; TCP/IP模型OSI模型TCP/IP对等模型应用层应用层表示层应用层会话层主机到主机层传输层传输层因特网层网络层网络层网络接入层数据链…

jsonwebtoken生成token和解析

先上npm地址 jsonwebtoken&#xff1a;jsonwebtoken - npm express-jwt&#xff1a;express-jwt - npmps const express require(express); const jwt require(jsonwebtoken); const { expressjwt: expressJWT} require(express-jwt)const app express();// 设置密钥 co…

爱智EdgerOS之深入解析数据库模块的Redis Client

一、Redis 简介 无论是什么类型的应用&#xff0c;都少不了和数据打交道。尤其是一些复杂的应用场景&#xff0c;都少不了一个高效可靠的数据库。例如日常开发中最常见的 MySQL 等关系型数据库&#xff0c;让数据的存储、检索轻松简单起来&#xff0c;甚至可以轻松地处理百万量…

51单片机c语言烧录软件,51单片机烧写程序的方法

STC89C51是应用广泛的51单片机&#xff0c;很多人都是通过该单片机入门学习的&#xff0c;单片机的学习需要勤动手。单片机需要烧写程序&#xff0c;要用到相关的软件和硬件。下面介绍一下51单片机烧写程序的方法。 1 所用到的硬件工具 51单片机烧写程序需要用到单片机的UART…

C语言数组(下)

我希望各位可以在思考之后去看本期练习&#xff0c;并且在观看之后独立编写一遍&#xff0c;以加深理解&#xff0c;巩固知识点。 练习一&#xff1a;编写代码&#xff0c;演⽰多个字符从两端移动&#xff0c;向中间汇聚 我们依旧先上代码 //编写代码&#xff0c;演⽰多个字…

数据库Delete的多种用法

数据库的Delete操作是用来删除数据库中的数据记录的&#xff0c;它是数据库操作中的一种重要操作&#xff0c;能够帮助用户删除不需要的数据&#xff0c;以便保持数据库的整洁和高效。在使用Delete操作时&#xff0c;需要注意确保操作的准确性和安全性&#xff0c;以免误删重要…

基于 Gin 的 HTTP 中间人代理 Demo

前面实现的代理对于 HTTPS 流量是进行盲转的&#xff0c;也就是说直接在 TCP 连接上传输 TLS 流量&#xff0c;但是我们无法查看或者修改它的内容。当然了&#xff0c;通常来说这也是不必要的。不过对于某些场景下还是有必要的&#xff0c;例如使用 Fiddler 进行抓包或者监控其…

触想嵌入式工业一体机在智能垃圾分类站的应用

1、行业发展背景 根据住建部给出的目标&#xff0c;到2025年前&#xff0c;全国地级及以上城市要基本建成垃圾分类处理系统。随着垃圾分类政策在全国强制落地&#xff0c;终端执行层面面临的最迫切问题是垃圾分类的准确性与社会参与意愿&#xff0c;而这两点与垃圾分类操作的简…

CNN发展史脉络 概述图整理

CNN发展史脉络概述图整理&#xff0c;学习心得&#xff0c;供参考&#xff0c;错误请批评指正。 相关论文&#xff1a; LeNet&#xff1a;Handwritten Digit Recognition with a Back-Propagation Network&#xff1b; Gradient-Based Learning Applied to Document Recogniti…

Python 中的数学运算(Python Math)

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com Python中的math模块是数学运算的重要工具&#xff0c;提供了丰富的数学函数和常数。本文将深入探讨math模块的功能和用法&#xff0c;使您能够更好地利用Python进行数学运算。 Python的math模块是一个强大的工具…

C51--OLED

GME12864-12 OLED写入指令数据&#xff1a; 1、start&#xff08;&#xff09;开始 2、slave address 存积地址&#xff1a;011110 xx 写入&#xff1a;b 0111 1000 &#xff08;0x78&#xff09;&#xff08;R / W位置为0时&#xff0c;表示写入&#xff09; 3、ACK 4、cotro…

操作系统———磁盘调度算法模拟

实验目的 磁盘是可供多个进程共享的设备&#xff0c;当有多个进程都要求访问磁盘是&#xff0c;应采用一种最佳调度算法&#xff0c;以使各进程对磁盘的平均访问时间最小。目前最成用的磁盘调度算法有先来先服务&#xff08;FCFS&#xff09;&#xff0c;最短寻道时间优先&…

Spring Boot的配置文件

配置文件的作用 整个项目中所有重要的数据都是在配置文件中配置&#xff0c;如数据库的连接信息&#xff0c;项目的启动端口&#xff0c;用于发现和定位问题的普通日志和异常日志等等。配置文件可以分为两类 系统使用的配置文件&#xff08;系统配置文件&#xff09;&#xf…

【Kotlin】

Lambda 就是一小段可以作为参数传递的代码。 因为正常情况下&#xff0c;我们向某个函数传参时只能传入变量&#xff0c;而借助Lambda 却允许传入一小段代码。 Lambda 表达式的语法结构&#xff1a; {参数名1: 参数类型, 参数名2: 参数类型 -> 函数体}首先&#xff0c;最外…

JS基础源码之手写模拟new

JS基础源码之手写模拟new 手写模拟new初步实现最终实现 手写模拟new new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象类型之一。 我们先看看new实现了哪些功能&#xff1a; function Person (name,age){this.name name;this.age age;this.habit Games;…

开发猿的平平淡淡周末---2023/12/9

上周回顾 完成了遗留的开发任务&#xff0c;基本全部完成进一步了解了系统当时设计的原理熟悉了代码的重构 2023.12.9 天气晴 温度适宜 前言 小伙伴们大家好&#xff0c;时间很快&#xff0c;又来到了周末&#xff0c;也是一个平平淡淡的周末。上周只更了一篇博客...原…

渗透测试 | 渗透测试之信息收集

渗透测试&#xff08;penetration test&#xff0c;pentest&#xff09;是实施安全评估&#xff08;即审计&#xff09;的具体手段。 渗透测试可能是单独进行的一项工作&#xff0c;也可能是常规研发生命周期&#xff08;例如&#xff0c;Microsoft SDLC&#xff09;里 IT 安全…

Unicode编码解码

一、Unicode概述 Unicode是一种字符编码标准&#xff0c;旨在解决不同字符集之间的兼容性问题。它为全球所有语言提供了一种统一的编码方式&#xff0c;使得各种字符能够在计算机系统中正确显示和处理。Unicode字符集包含了世界上几乎所有的字符&#xff0c;包括中文字符、英文…

算法Day23 简单吃饭(0-1背包)

简单吃饭&#xff08;0-1背包&#xff09; Description Input Output Sample 代码 import java.util.Scanner; public class Main {public static void main(String[] args) {Scanner scanner new Scanner(System.in);int n scanner.nextInt();int total scanner.nextInt(…