【赤石C++】使用宏魔法在C语言中实现协程

admin 2026-02-10 14:51:32 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文介绍利用C语言宏和switch-case技巧实现协程的方法,通过crBegin、crReturn、crFinish三个宏配合静态变量保存状态,利用__LINE__宏生成唯一case标签实现执行流跳转,达到函数暂停与恢复的效果。该技术源自达夫设备变种,展示了C语言底层编程技巧,但存在代码可读性差、依赖静态变量等局限,适合嵌入式等特定场景使用。 综合评分: 65 文章分类: 安全开发,二进制安全,其他


cover_image

【赤石C++】使用宏魔法在 C 语言中实现协程

原创

crackme.net crackme.net

crackme安全实验室

2026年2月9日 04:52 河南

协程

协程(Coroutine) 可以看作是“可暂停和恢复的函数”。与普通函数只能“调用-返回”一次不同,协程可以在执行过程中多次暂停(yield)并交出控制权,之后又能从上次暂停的地方继续执行

比如:

def my_coroutine():
    for i in range(3):
        yield i  # 暂停并返回 i

gen = my_coroutine()
print(next(gen))  # 输出 0
print(next(gen))  # 输出 1
print(next(gen))  # 输出 2

每次调用next(),协程就从上次yield的地方继续执行

C 语言实现协程

赤过“达夫设备”这篇文章的都知道,switch 语句的 case 标签可以出现在 switch 内部任意位置,甚至嵌套在另一个循环里

【赤石C++】详解达夫设备

#include&nbsp;<iostream>

#define&nbsp;crBegin static int state = 0; switch (state) { case 0:
#define&nbsp;crReturn(x) do { state = __LINE__; return x; case __LINE__:; } while (0)
#define&nbsp;crFinish }

int&nbsp;my_coroutine()&nbsp;{
&nbsp; &nbsp;&nbsp;staticint&nbsp;i;

&nbsp; &nbsp; crBegin;
&nbsp; &nbsp;&nbsp;for&nbsp;(i =&nbsp;0; i <&nbsp;3; ++i) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;crReturn(i);
&nbsp; &nbsp; }
&nbsp; &nbsp; crFinish;
}

int&nbsp;main()&nbsp;{
&nbsp; &nbsp; std::cout <<&nbsp;my_coroutine() << std::endl;&nbsp;// 输出 0
&nbsp; &nbsp; std::cout <<&nbsp;my_coroutine() << std::endl;&nbsp;// 输出 1
&nbsp; &nbsp; std::cout <<&nbsp;my_coroutine() << std::endl;&nbsp;// 输出 2
}

(如果你使用 MSVC,这段代码可能需要 Release 模式才能编译)

乍一看有点魔法,我们不妨先手动将宏展开再进行分析

int&nbsp;my_coroutine_no_macro()&nbsp;{
&nbsp; &nbsp;&nbsp;staticint&nbsp;i;

&nbsp; &nbsp;&nbsp;/* --- crBegin; 展开开始 --- */
&nbsp; &nbsp;&nbsp;staticint&nbsp;state =&nbsp;0;
&nbsp; &nbsp;&nbsp;switch&nbsp;(state) {
&nbsp; &nbsp;&nbsp;case0:;
&nbsp; &nbsp;&nbsp;/* --- crBegin; 展开结束 --- */

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;for&nbsp;(i =&nbsp;0; i <&nbsp;3; ++i) {

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;/* --- crReturn(i); 展开开始 --- */
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;do&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; state =&nbsp;23; &nbsp;// 假设这行是第 23 行(__LINE__ 宏展开结果)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;i;
&nbsp; &nbsp;&nbsp;case23:;&nbsp;// 这一行也是 23,我为了方便阅读手动加上回车了
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;while&nbsp;(0);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;/* --- crReturn(i); 展开结束 --- */

&nbsp; &nbsp; &nbsp; &nbsp; }

/* --- crFinish; 展开开始 --- */
&nbsp; &nbsp; };
/* --- crFinish; 展开开始 --- */
}

执行流程:

首次调用时

  • • 初始时 state = 0switch 进入 case 0 分支
  • • case 0 后面跟的是一条空语句(一个分号),所以 fall-through 到 for 循环起始处
case&nbsp;0:;
/* fall through */

&nbsp; &nbsp;&nbsp;// 穿透到 for 循环处
&nbsp; &nbsp;&nbsp;for(i =&nbsp;0; i <&nbsp;3; ++i)

/* ...... */
  • • do { ... } while(0) 不需要特别分析,这个是常用的编程技巧,本文不会涉及
  • • 进入 for 循环后,将 state 设置为 23,并返回初始 i = 0

再次调用时

  • • 由于 state = 23switch 语句进入 case 23 分支
  • • 同样的,case 23 后面跟的也是一条空语句,所以fall-through 到 for 循环末尾,并进行条件判断
  • • 条件判断成立时,for 循环跳转到开头再次执行,由于 i 是静态变量,保存了上一次调用的状态,所以返回 i = 1

参考

https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html (顺带一提,这位大神还是 PuTTY 的开发者)

https://zh.wikipedia.org/wiki/%E5%8D%8F%E7%A8%8B


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:crackme安全实验室 crackme.net crackme.net《【赤石C++】使用宏魔法在 C 语言中实现协程》

评论:0   参与:  3