当前位置:  开发笔记 > 编程语言 > 正文

使用GCC和clang __attribute __((cleanup))和指针声明的一种好的惯用方法

如何解决《使用GCC和clang__attribute__((cleanup))和指针声明的一种好的惯用方法》经验,为你挑选了2个好方法。

我认为GCC扩展__attribute__((cleanup))是一个好主意,至少在某些情况下,但我无法弄清楚如何以一种好的方式使用它.我所做的一切看起来仍然很烦人.

我看到了很多的代码做#define _cleanup_(x) __attribute__((cleanup(x))只是为了少打字,但它有没有办法通过有没有一个标准功能一样free或者closedir,fclose等?

我看到我不能写:

__attribute__((cleanup(free))) char *foo = malloc(10);

因为清理回调会收到char**指针,所以我必须总是这样写:

static void free_char(char **ptr) { free(*ptr); }
__cleanup__((free_char)) char *foo = malloc(10);

这非常烦人,最烦人的部分是为你需要的所有类型定义这样的清理函数,因为显然你不能只为它定义它void **.避免这些事情的最佳方法是什么?



1> Ismail Badaw..:

你不能写__attribute__((cleanup(free))),但你不需要free为每种类型编写一个清理函数.这很难看,但你可以这样写:

static void cleanup_free(void *p) {
  free(*(void**) p);
}

我第一次在systemd代码库中看到了这一点.

对于其他函数,您通常需要编写一个包含额外级别间接的包装器以供使用__attribute__((cleanup)).systemd 为此定义一个辅助宏:

#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func)             \
    static inline void func##p(type *p) {                   \
            if (*p)                                         \
                    func(*p);                               \
    }                                                       \
    struct __useless_struct_to_allow_trailing_semicolon__

它用于所有的地方,例如,

DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose);

#define _cleanup_pclose_ __attribute__((cleanup(pclosep)))


可能值得注意的是`cleanup_free`从`T **`=>`void *`=>`void **`进行的转换[(严格来说)不一定可以安全地移植] [https:/ /stackoverflow.com/a/16557330/179715),这就是为什么需要显式`*(void **)`跳舞的原因。

2> Leushenko..:

有一个库可以在这里建立通用智能指针(unique_ptrshared_ptr)__attribute__((cleanup)):https://github.com/Snaipe/libcs​​ptr

它允许您编写更高级别的代码,如下所示:

#include 
#include 
#include 

void print_int(void *ptr, void *meta) {
    (void) meta;
    // ptr points to the current element
    // meta points to the array metadata (global to the array), if any.
    printf("%d\n", *(int*) ptr);
}

int main(void) {
    // Destructors for array types are run on every element of the
    // array before destruction.
    smart int *ints = unique_ptr(int[5], {5, 4, 3, 2, 1}, print_int);
    // ints == {5, 4, 3, 2, 1}

    // Smart arrays are length-aware
    for (size_t i = 0; i < array_length(ints); ++i) {
        ints[i] = i + 1;
    }
    // ints == {1, 2, 3, 4, 5}

    return 0;
}

至于惯用语,但是?那么上面肯定接近惯用的C++.不是那么多.GCC和Clang显然主要支持该功能,因为它们也有C++编译器,所以他们可以选择在C前端使用RAII机器而无需额外费用.以这种方式编写C-intention-as-C并不是一个好主意.它有点依赖于C++编译器,尽管实际上并没有被使用.

如果是我,我可能会调查实现自动释放池,或类似的事情,可以在语言级别的纯C中实际完成.取决于您需要多快地释放资源; 对于记忆,你通常可以在没有立即清理的情况下生活.

推荐阅读
wurtjq
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有