生成C迭代器宏以pre-C99编译器 [英] Building a C iterator macro with a pre-C99 compiler

查看:109
本文介绍了生成C迭代器宏以pre-C99编译器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的code,它必须以pre-C99编译器(我们正在努力更新,但它是一个艰巨的任务)进行编译,被调用到一个实用程序库设计的C99的初衷。特别是,这些实用程序定义一个HashMap类型,并提供一个宏通过它类似于以下迭代:

My code, which must be compiled with a pre-C99 compiler (we're working on updating but it's an enormous task), is calling into a utility library designed with C99 in mind. In particular, these utilities define a hashmap type and provide a macro to iterate through it similar to the following:

#define MAP_FOREACH(key, val, map) \
    for (struct _map_iterator iter __attribute__((cleanup(_map_iter_cleanup))); \
        (key) = iter->pair->key, \
        (value) = iter->pair->value; \
        iter = iter->get_next_cb())

实际code有更多的给它一点(的功能,以确保迭代器的名称是独一无二的,等等),但是这包括我的问题的肉这是C是pre-1999年版本不支持初始化内部变量循环。现在,这里明显的解决将是移动初始化循环之外,用code,看起来像:

The actual code has a bit more to it (functionality to make sure the iterator's name is unique, etc.), but this covers the meat of my problem which is that pre-1999 versions of C don't support initializing variables inside a for loop. Now the obvious fix here would be to move the initialization outside of the loop, with code that looks like:

// Doesn't work
#define MAP_FOREACH(key, val, map) \
    struct _map_iterator iter __attribute__((cleanup(_map_iter_cleanup)));
    for (; \
        (key) = iter->pair->key, \
        (value) = iter->pair->value; \
        iter = iter->get_next_cb())

问题是, __ __属性((清理(_map_iter_cleanup)))位。按照 GCC文档,定义连接到清理code变量,当变量超出作用域而被运行。因为我们已经搬到外面的for循环迭代器的声明,其范围已经变了,清理code被其他地方运行。不幸的是,图书馆的其他部分依赖越来越迭代器立即清理 - 地图跟踪有多少迭代器已经启动,并抛出如果他们都走了之前它破坏了一个错误

The issue is that __attribute__((cleanup(_map_iter_cleanup))) bit. According to the GCC documentation, that defines cleanup code attached to the variable, which gets run when the variable goes out of scope. Because we've moved the iterator declaration outside the for loop, its scope has changed, and the cleanup code gets run elsewhere. Unfortunately, other parts of the library rely on the iterator getting cleaned up immediately - the map keeps track of how many iterators have been initiated, and throws an error if it's destroyed before they're all gone.

我一直在尝试和失败,现在想解决这个干净的方法了几天,但我的短来了。我真的不希望重新实现在pre-C99 code宏观加清理,但使用这个库。所有的地方和改变API包括一个迭代后的清理通话会是痛苦的,何况不雅。

I've been trying and failing to think of a clean way around this for a few days now, but I'm coming up short. I don't really want to re-implement the macro-plus-cleanup in the pre-C99 code, but this library is used all over the place and changing the API to include a post-iteration cleanup call would be painful, not to mention inelegant.

有没有人遇到过这样的事情,知道变通的办法?

Has anyone encountered this sort of thing before and know a way around it?

编辑:我们使用GCC 4.2.2与-std = C89选项

we're using GCC 4.2.2 with the -std=c89 option

推荐答案

一种可能性是创建必须C89 code被用来替代宏。你必须延伸范围和封装的动作,例如通过使一组新的宏如下:

One possibility is to create an alternative macro that must be used in C89 code. You'd have to extend the scope and encapsulate the action, such as by making a new set of macros as follows:

/* Force a compiler error if non-C99 code uses the C99 macro. */
#if __STDC_VERSION__ >= 199901L
/* C99 code */
#define MAP_FOREACH(key, val, map) \
    for (struct _map_iterator iter __attribute__((cleanup(_map_iter_cleanup))); \
        (key) = iter->pair->key, \
        (value) = iter->pair->value; \
        iter = iter->get_next_cb())
#endif

/* C89-compatible macro */
#define MAP_FOREACH_DO(key, val, map, statement) \
do{ struct _map_iterator iter __attribute__((cleanup(_map_iter_cleanup))); \
for (; \
    (key) = iter->pair->key, \
    (value) = iter->pair->value; \
    iter = iter->get_next_cb()) \
    { \
        statement; \
    } \
}while(0)

这样的简单语句你可以这样做:

That way for simple statements you can just do something like:

MAP_FOREACH_DO(...的printf(%s =%s的\\ n键,值));

...和更复杂的语句就可以调用的函数。

... and for more complex statements you can call a function.

在理想情况下,当然,你只需切换到C99(至少在有关code)和用它做。

Ideally, of course, you just switch to C99 (at least for the relevant code) and be done with it.

这篇关于生成C迭代器宏以pre-C99编译器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆