C99 goto label地址实现C语言协程

本文介绍如何利用C99的goto语句特性实现简单的协程机制,通过存储标签地址并使用宏定义简化流程控制,提高了代码的效率与可读性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以前用C语言中的switch case实现过一个简单的协程,并应用到了实际的项目里。文章在这里,C语言实现协程,最近了解到C99中,goto语句可以跳转到一个变量里,变量保存的是label的地址。于是瞬间想到,这个可以替换协程实现中的switch case的机制。


首先,说明一下什么是goto到标签地址。

int main() 
{
     static void* p = &&label;
     goto *p;

     printf("before label\n");
     label:
     printf("after label\n");

     return 0;
}

  • &&label是语法,&&就是获得label的地址,并不是取地址在取地址。
  • goto *p 就是跳转到p指针,所指向的地址。
  • 如果p指向了的是不正确的地址,程序会运行时崩溃。
  • label地址需要用void*指针才存放。

那么,现在我们看怎么用这个机制来实现协程。之前需要阅读, C语言实现协程,重复内容不再叙述。只贴出改造的的部分。

/**
 * Construct goto label with line number
 */
#define _ACoroutineLabel(line) label##line
#define  ACoroutineLabel(line) _ACoroutineLabel(line)


#define ACoroutineBegin()                      \
    if (coroutine->step != NULL)               \
    {                                          \
        goto *coroutine->step;                 \
    }                                          \
    coroutine->state = coroutine_state_running \


#define ACoroutineEnd() \
    coroutine->state = coroutine_state_finish


#define ACoroutineYieldFrame(waitFrameCount)               \
    coroutine->waitValue    = waitFrameCount;              \
    coroutine->curWaitValue = 0.0f;                        \
    coroutine->waitType     = coroutine_wait_frame;        \
    coroutine->step         = &&ACoroutineLabel(__LINE__); \
    return;                                                \
    ACoroutineLabel(__LINE__):


#define ACoroutineYieldSecond(waitSecond)                  \
    coroutine->waitValue    = waitSecond;                  \
    coroutine->curWaitValue = 0.0f;                        \
    coroutine->waitType     = coroutine_wait_second;       \
    coroutine->step         = &&ACoroutineLabel(__LINE__); \
    return;                                                \
    ACoroutineLabel(__LINE__):


#define ACoroutineYieldCoroutine(waitCoroutine)            \
    coroutine->waitValue    = 0.0f;                        \
    coroutine->curWaitValue = 0.0f;                        \
    coroutine->waitType     = coroutine_wait_coroutine;    \
    AArrayListAdd((waitCoroutine)->waits, coroutine);      \
    coroutine->step         = &&ACoroutineLabel(__LINE__); \
    return;                                                \
    ACoroutineLabel(__LINE__):

  1.  首先,我们把coroutine->step改成void*类型,存储label标签地址。
  2.  ACoroutineLabel 是为了展开__Line__定义,构造label + 行号的标签名称。
  3. 接下来就是,在每次进入协程函数的时候,直接goto到step存储的标签上。
  4. 没有了switch case,就避免了switch嵌套的可能性错误。并且提升了效率。
  5. 协程函数用使用的,中断宏定义,就是退出+打标签,下次goto到标签处继续运行。

最后,看看使用的样子。

static void LoadingRun(Coroutine* coroutine)
{
    static int progress = 0;
//--------------------------------------------------------------------------------------------------
    ACoroutineBegin();
    for (; progress < progressSize; progress++)
    {
        ACoroutineYieldFrame(0);
    }
    ACoroutineYieldSecond(1.0f);
    ACoroutineEnd();
}
static void OnReady()
{
    ACoroutine->StartCoroutine(LoadingRun);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值