【问题标题】:Generic cleanup attribute for malloced memorymalloced 内存的通用清理属性
【发布时间】:2019-05-27 17:04:41
【问题描述】:

GCC-specific attribute cleanup。可以这样使用:

#define SCOPED_FILE __attribute__((cleanup(cleanup_file)))

void
cleanup_file(FILE **file) {
    if (*file != NULL) { fclose(*file); }
}
…
FILE *SCOPED_FILE file = fopen(…); // file will be closed at the end of scope.

我认为为任何malloced 内存提供清理功能会很方便。不得不规避铸造问题,我想出了以下实现:

#define SCOPED_MEM __attribute__((cleanup(cleanup_mem)))

static inline void
cleanup_mem(void *pmem) {
    void *mem = *(void **)pmem;
    free(mem);
}

int main(void) {
    char *SCOPED_MEM str = malloc(20);
    strcpy(str, "pineapple");
    printf("hi, %s\n", str);
    // str will be free'd at the end of scope
}

它确实有效,但闻起来很有趣,因为我没有直接将void ** 指定为参数类型,而是强制转换为它。 我想知道,它是否有一些我现在看不到的问题。

【问题讨论】:

  • 看不懂void *mem = *(void **)pmem;的意思。
  • 您能解释一下您为什么要使用它吗?在函数结束之前添加一些拆解代码并不是很难。
  • @Cheatah,它在这么简单的函数中用处不大,而是在具有多个退出点的函数中有用。在这种情况下,您不需要在每个点手动调用清理函数。
  • @EugeneSh。我将void * 转换为void ** 并取消引用它
  • stackoverflow.com/questions/34574933/…第二个回答同意这种做法。

标签: c gcc


【解决方案1】:

但闻起来很有趣,因为我没有直接将void ** 指定为参数类型,而是强制转换为它。

C 中的强制转换通常是代码异味,因此您应该问自己:为什么需要强制转换?

一个人的第一个方法可能是:

static inline void
cleanup_mem(void **pmem) {
    free(*mem);
}

但编译器不会让您将T** 隐式转换为void**,因为严格来说,it's not necessarily safe

使cleanup_mem 采用void* 并在内部转换为void** 不会使转换变得更安全。

【讨论】:

  • 那么,不可能做我想做的事吗?除了进一步限制平台选择。
  • @grepcake 在实践中,void** 演员可能应该没问题(但您的代码应该验证sizeof (T**) == sizeof (void **) 作为预防措施),所以我不会太担心它。无论如何,使用gcc 扩展名已经限制了可移植性。就我个人而言,我只会使用a single-entry, single-exit idiom with goto 编写可移植代码。
猜你喜欢
  • 1970-01-01
  • 2017-11-30
  • 1970-01-01
  • 2017-05-19
  • 2013-01-11
  • 2016-10-02
  • 2011-11-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多