使用 Clang 的嵌套函数重写 GCC 清理宏?

2023-12-07

我正在尝试解决第三方库的问题。问题是该库使用隐藏在宏中的 GCC 嵌套函数,而 Clang 不支持嵌套函数并且没有计划这样做(参见,Clang Bug 6378 - 错误:函数上的存储类非法).

这是我和 Clang 的痛点的宏:

#define RAII_VAR(vartype, varname, initval, dtor) \
    /* Prototype needed due to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36774 */ \
    auto void _dtor_ ## varname (vartype * v); \
    void _dtor_ ## varname (vartype * v) { dtor(*v); } \
    vartype varname __attribute__((cleanup(_dtor_ ## varname))) = (initval)

这是它的使用方式(来自代码注释):

 * void do_stuff(const char *name)
 * {
 *     RAII_VAR(struct mything *, thing, find_mything(name), ao2_cleanup);
 *     if (!thing) {
 *         return;
 *     }
 *     if (error) {
 *         return;
 *     }
 *     do_stuff_with_thing(thing);
 * }

The 铿锵用户手册l 声明使用 C++ 和 lambda 函数来模拟。我不确定这是最好的策略,C 项目可能会not接受 C++ 补丁(他们可能会先 tar 并羽毛化我)。

有没有办法重写宏,使其 (1) 更适合 Clang,并且 (2) 保留原始函数语义?


Clang 不支持 GCC 嵌套函数,但它支持Objective C 风格的“块”,即使在 C 模式下:

void f(void * d) {
    void (^g)(void *) = ^(void * d){ };
    g(d);
}

您需要使用以下命令调用它clang命令而不是gcc,并且还(?)通过-fblocks -lBlocksRuntime给编译器。

您不能将块用作cleanup直接值,因为它必须是一个函数名称,所以(窃取想法here)你需要添加一个间接层。定义一个函数来清理空块,并使您的 RAII 变量成为block您想要在范围末尾运行:

typedef void (^cleanup_block)(void);
static inline void do_cleanup(cleanup_block * b) { (*b)(); }

void do_stuff(const char *name) {
    cleanup_block __attribute__((cleanup(do_cleanup))) __b = ^{ };
}

因为块形成闭包,所以您可以将操作放在变量上以直接在内部进行清理that堵塞...

void do_stuff(const char *name) {
    struct mything * thing;
    cleanup_block __attribute__((cleanup(do_cleanup))) __b = ^{ ao2_cleanup(thing); };
}

...并且应该像以前一样在范围末尾运行,由块上的清理调用。重新排列宏并添加__LINE__所以它适用于多个声明:

#define CAT(A, B) CAT_(A, B)
#define CAT_(A, B) A##B

#define RAII_VAR(vartype, varname, initval, dtor) \
    vartype varname = (initval); \
    cleanup_block __attribute__((cleanup(do_cleanup))) CAT(__b_, __LINE__) = ^{ dtor(varname); };

void do_stuff(const char *name) {
    RAII_VAR(struct mything *, thing, NULL, ao2_cleanup);
    ...

无论如何,类似的事情。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Clang 的嵌套函数重写 GCC 清理宏? 的相关文章

随机推荐