说明:此文内容纯属个人看法,无所谓对错,欢迎拍砖!
call/cc(call-with-current-continuation)是函数编程的顶级概念,虽然我们用到的场合不是太多,但重要性非比寻常。
call/cc的魔力在于迫使运行的程序通过时光隧道返回到从前的某个时刻。
从返回的方式看我们可以有多种理解,下面是最常见的两种:
1、逐步退回:一步就是一次函数调用。执行call/cc时,程序自动执行函数返回操作(RET),直到返回的位置与call/cc的要求一致。
2、直接跳转:程序的指令系统直接切换到call/cc的位置,被抛掉的运行节点和对象留给GC处理。
命令式语言(如C/C++/PASCAL)可以很方便的实现第一种返回方式,比如使用异常和长跳转,但由于基于栈运行和缺乏GC支持,很难实现第二种返回方式。我们不在这里讨论语言的分类问题,而是通过一个例子,凭想象来推测一下call/cc背后都发生了些什么。
void b(function cc)
{
= "b";
cc(); // 返回a()中创建cc对象后的下一条指令位置
}
void a()
{
callcc cc() { = "a" }; // 创建cc对象,这里是个函数
b(cc);
}
现在运行函数a()并登记其运行过程:
a()开始执行。
|__创建call/cc函数cc()。
|__跳过cc()的返回执行代码。
|__将cc传递到b()函数中加以执行。
...b()开始执行
...|__打印字符'b'
...|__执行cc()。
......cc()开始执行
......|___中断b()回到a(),指令系统指向cc()的返回执行代码。
|__打印字符'a'
|__回到步骤4。
cc在第9步直接中断b()的运行回到a()并将指令系统指向cc()的返回执行代码,这一步是怎么发生的呢?
一、可以确定cc至少携带了以下两个信息:
1、a()的运行时信息(比如栈基址)。
2、cc返回执行代码的地址。
我们用结构ccrec来描述它们:
// call/cc 信息结构定义
struct ccrec {
void * addr; // 函数运行时信息的地址
unsigned long next; // 下一条指令的位置
}
指令系统可以假定为以下设计:
// 指令系统结构定义
struct isrec {
struct ccrec current; // 当前运行时信息
struct isrec *prior; // 上一级调用的指令系统结构
}
struct isrec *current; // 当前指令系统结构
void *get_call_base() // 提取当前运行时信息
{
return current->current.addr;
}
unsigned long get_next_instruction() // 返回下一条指令的地址
{
return current->current.next;
}
void set_next_instruction(unsigned long next) // 设置下一条指定的地址
{
current->current.next = next;
}
二、callcc创建cc对象后在其内部保存以上两条信息:
// callcc 指令的处理过程
void * cc = create_function(); // 创建 cc 函数
struct ccrec * rec = create_new_ccrec();
rec->addr = get_call_base(); // 提取当前函数运行时信息
rec->next = get_next_instruction(); // 下一条即将执行的的指令
save_ccrec(cc, rec); // 保存信息到cc对象
三、cc执行时重置了指令系统的状态:
// 提取call/cc返回信息
struct ccrec * rec = load_ccrec(cc);
// 执行返回操作
while (rec->addr != get_call_base())
exec_return(); //==> 它做了什么?
// 设置下一条指令
set_next_instruction(rec->next);
函数exec_return()不应该太复杂,大致的是如下的代码:
// 函数返回操作函数
void exec_return()
{
// 1. 加锁休眠垃圾回收并返回当前指令系统结构
struct isrec * curr = begin_return();
// 2. 将当前运行时信息登记到垃圾回收系统
gc_notify(curr);
// 3. 设置指令系统,返回上一级调用
current = curr->prior;
// 4. 完成返回操作后开锁,重新激活垃圾系统
end_return();
}
这样的想象和推测单从理解上说应该是完备的,基于这个理解,我们试着做些更深层次的发挥。
分享到:
相关推荐
为了更好地理解 `call/cc` 的工作原理,我们可以考虑一个简单的示例: ```scheme (define (break-point k) (k "Break!")) (define (demo) (call/cc break-point) (display "This will not be printed")) ``` 在...
在进行基于TI CC26XX系列无线MCU芯片的软件开发时,首先需要对相关的文档和开发环境有一个全面的了解。CC2640/2650是德州仪器(Texas Instruments,简称TI)推出的低功率无线MCU,支持蓝牙低功耗(Bluetooth Low ...
intent.putExtra(Intent.EXTRA_CC, ccs); intent.putExtra(Intent.EXTRA_SUBJECT, "邮件主题"); intent.putExtra(Intent.EXTRA_TEXT, "邮件正文"); intent.setType("message/rfc822"); startActivity(Intent....
【程序老媛出品,必属精品...资源名:opc ua客户端C C++示例源码.zip 资源类型:程序源代码 源码说明: 基于C C++写的OPC UA 客户端程序源码 包含完整源码和注释 很适合借鉴学习 适合人群:新手及有一定经验的开发人员
ISO C/C++ 和 Fortran 互操作性示例这是一组代码示例,展示了如何将 Fortran 9x/2003 代码合并到 C/C++ 和 Exelis IDL 中。这里有什么?...idl_call_fortran 此处的示例演示了如何从 IDL 调用已“C 有界
控制流的中间状态(称为Context )可以随时保存和恢复(如 call/cc),这也使得调用基于传统异步接口的回调变得更加容易。 大多数原始任务都是无状态的,这意味着组合任务可以在大多数情况下重用。 凯特很容易...
$(info CC is $(CC)) ``` ##### 6.10 特定目标变量的值 - 可以为特定目标定义变量。 - 示例: ``` hello-CFLAGS = -DHELLO_WORLD ``` ##### 6.11 特定格式变量的值 - 根据目标文件的格式设置变量。 - 示例: ...
特别是ICall模块,它提供了蓝牙协议栈服务,初级服务的介绍,初始化与注册的流程,以及线程同步和示例用法。 最后,文档的最后一部分专注于BLE协议栈的介绍,涵盖了GAP(通用访问配置文件)和GATT(通用属性配置...
通过具体的示例代码,我们将逐步解析这一过程的关键步骤和技术细节。 #### 二、环境搭建与配置 在开始之前,确保您的开发环境已经准备妥当。对于AS3部分,您需要安装Adobe Flash Professional或者Adobe Animate CC...
### 示例代码分析 #### XML源文档(`test.xml`) ```xml <data_info CC_ID='195,196,197,198'/> ``` 在这个例子中,`<data_info>`元素包含了一个名为`CC_ID`的属性,其值由逗号`,`分隔的一系列数字组成。 #### ...
- **示例**: `CALL C:\Scripts\MyBatch.cmd` ##### 2.8 CD - **命令**: `CD [drive:][\path]` - **描述**: 显示或更改当前目录。 - **示例**: `CD C:\Users\John` 进入 `John` 用户的主目录。 ##### 2.9 CHCP - **...
下面通过具体示例来进一步了解call()方法的用法: 假设我们有两个函数add和sub,其中add负责计算两个数的和,而sub负责计算两个数的差。我们想要用add方法替换sub方法来执行加法操作。可以这样做: ```javascript ...
CALL MYLIB(CC) '123' ``` - **解释:** 执行位于用户名 `.MYLIB.LOAD` 下的 `CC` 程序,并将 `'123'` 作为运行参数。 - **调用 PL/1 程序:** ```plaintext CALL 'MY.PCP.LOAD(MOD1)' '/123' ``` - **解释...
- **Oracle C API**:Oracle提供了OCI (Oracle Call Interface),这是一种强大的API集合,用于在C/C++程序中实现对Oracle数据库的操作。 - **示例代码**: ```c++ // MySQL C API 示例 MYSQL *conn; MYSQL_RES *...
- 示例:`CALL K PC + 1 -> [SP] (PAGE,K) -> PC 1SubroutineCall` 4. **DISI (Disable Interrupts):** 禁用中断。 - 示例:`DISI 1DisableInterrupt` 5. **ENI (Enable Interrupts):** 启用中断。 - 示例:`...
#### 示例代码分析 在混合编程实践中,理解具体的代码实现是至关重要的。例如,下面的代码展示了如何使用在线汇编修改 CPSR 的值: ```c void disable_interrupts() { asm volatile ( "mrs %0, cpsr\n\t" // ...
#### 六、示例分析 假设要在培训服务器(SAPTRN)上调用开发服务器(SAPDEV)上的`Z_GET_CC_MAILADDR`函数: 1. **创建RFC连接**:在SAPTRN上创建连接到SAPDEV的RFC目的地,指定连接细节。 2. **编写ABAP程序**:编写...
/PROG PIPE_2SS1CC /ATTR OWNER = MNEDITOR; COMMENT = "START_STOP"; PROG_SIZE = 8121; CREATE = DATE 10-11-25 TIME 14:22:04; MODIFIED = DATE 10-11-25 TIME 16:33:18; FILE_NAME = PIPE_2SS; VERSION = 0; ...
- 示例:`CC=$(CC_BASE)gcc` 3. **变量高级用法** - 使用 `$(filter)`、`$(patsubst)` 等函数可以进行更复杂的字符串处理。 4. **追加变量值** - 使用 `+=` 运算符可以追加变量值。 - 示例:`LIBS += -lm` 5....