给定以下源代码:
#include <stddef.h>
#include <sys/types.h>
#include <dirent.h>
static inline void closedirp(DIR **p) {
if (*p)
closedir(*p);
}
#define auto_cleanup(resource) _Generic((resource), \
DIR **: closedirp, \
)(resource)
int main() {
#ifdef GENERIC
__attribute__((cleanup(auto_cleanup))) DIR * t2 = NULL;
t2 = opendir("/tmp");
#else
__attribute__((cleanup(closedirp))) DIR * t1 = NULL;
t1 = opendir("/tmp");
#endif
}
它编译和运行时没有泄漏,没有定义。但是,当定义泛型时,编译将失败:
$ gcc foo.c -DGENERIC
foo.c: In function ‘main’:
foo.c:16:2: error: cleanup argument not a function
__attribute__((cleanup(auto_cleanup))) DIR * t2 = NULL;
^
这对泛型的使用是毫无意义的,但是我想扩展它并处理许多类型的资源来自动清理。
最佳答案
_Generic
不是函数,而是启动主表达式的关键字。
但在这里,你似乎更是走错了方向:auto_cleanup
是一个宏。类似于宏的函数有一个特殊性,即如果在它之后没有()
提交,它们就不会被扩展。在这里,您只需将标识符auto_cleanup
保留在编译的稍后阶段。但是这个标识符在后面的阶段没有声明为任何东西。
总结一下:
如果使用正确,宏将在编译的早期阶段被文本替换
随后的阶段会看到一个_Generic
表达,并决定该_Generic
表达的哪个分支
只有那个分支才能“存活”并在代码的那个部分编译
在所有这一切中,没有任何函数或函数指针可用于gcc的cleanup
扩展。