C语言小技巧:带扫尾工作的宏

前两天为了在C下编写一个类似Erlang式消息传递的框架,需要定义一个receive宏,使得coroutine处理函数的编写可以类似这样:

int foo()
{
    ...
    receive(msg)
    {
        // Deal with the message
    }
    ...
    receive(msg)
    {
        // Deal with another message
    }
    ...
}

因为foo()函数以coroutine方式执行,所以消息的及时释放就显得尤为重要了,receive()之后紧接的代码块就是这个消息的生存周期,完成之后需要立即对消息进行释放。这就对receive宏的编写提出了一个特别的要求:包含扫尾工作。

最后定义出来的宏是这样的:

#define receive(msg) if (0); for (msg = co_recvmsg(); msg; co_freemsg(msg), msg = NULL)

co_recvmsg()是一个阻塞式的消息接收函数,co_freemsg()就是那个负责释放消息的接口。开头的“if 0”则是为了避免当在同一层次中两次调用receive时使用相同的参数名可能导致的VC下编译错误(GCC没有这个问题)。

如果开启了优化选项,编译器将消除上述宏展开后的循环体,最终优化后的代码实际等效于:

// Source: receive(msg) { ... }
{
    msg = co_recvmsg();
    if (msg)
    {
        ...
    }
    co_freemsg(msg);
    msg = NULL;
}
Written on July 27, 2008