return C 中的静态数组以避免内存泄漏是一种好习惯吗?

Is it good practice to return static arrays in C to avoid memory leaks?

我对在函数中使用静态数组作为 return 值以避免相当复杂地使用 free().

有一些疑问

我负责解决 C 程序中的一些内存泄漏问题。当直接将宏作为函数参数调用时会发生这些泄漏:

snprintf( ..., MACRO, ...);

当满足某些条件时,这个宏调用一个使用malloc()分配内存的函数:

#define MACRO ({ \
    char * problematicVariable = ... ? problematicFunction(NULL) : fixedValue; \
    // Some if statements... 
    problematicVariable; \
})

在程序中实现 promlematicFunction()MACRO 的方式使得无法正确释放内存,除非进行大量更改,因此我碰巧找到的解决方法是释放直接在 problematicFunction() 内的内存,在将其值复制到静态数组后:

char *problematicFunction(char *arg) 
{
    char *buff = malloc(PATH_MAX);
    static char temp[PATH_MAX];

    // Doing stuff with buff...

    if (strlcpy(temp, buff, sizeof(temp)) >= sizeof(temp))
    {
        // Handle error...
    }

    free(buff);
    return(temp);
}

这样的事情可以被认为是好的做法吗? return 值应该是只读的。

提前致谢!

这取决于上下文。在大多数托管系统中,使用具有静态存储持续时间的内部变量或返回指向它们的指针是不受欢迎的。因为这使得函数不适合多线程 - 它们不是 线程安全的 除非您显式添加互斥锁或类似机制。编写函数 re-entrant,调用者分配并且没有全局资源等被认为是可能的最佳实践。

当然,如果该函数不重置静态存储资源,则只能调用一次。这对于“单例”设计模式是有意义的,但对于通用库则不是。

然而,在独立(嵌入式等)系统中,您经常使用静态内存池,因为此类系统通常是单线程的,并且禁止使用堆分配。

通常,如果 执行 malloc 的代码模块也是负责清理其自身混乱的代码模块,为此提供一个函数,它是所有必要 free() 调用的包装器。对于每个 malloc 调用,在相同的代码中应该有一个相应的自由调用。这也适用于所有其他动态资源,文件句柄、线程等。

过去约 40 年的 C 编程历史表明,当您提出功能失调的库 API(例如 POSIX getline)时,内存泄漏最常出现,调用者是负责手动清理图书馆分配的东西。如果库改为使用具有私有封装的适当设计,则不应发生内存泄漏。

现在 C 语言当然没有 RAII 或析构函数,因此必须信任使用库的 C 程序员激活他们的大脑并调用一个函数 foo_cleanup() 如果“foo 库”提供了一个函数并且告诉程序员在使用完资源后调用它。

返回静态缓冲区是可以的,但仅限于单线程环境。 标准 C 库中的许多函数都是以这种方式实现的(例如 strerror 函数)。 如果你想让它们线程安全,你必须将缓冲区作为参数传递给函数(strerror_r)。 在这种情况下,由调用者在静态、动态内存或堆栈中分配缓冲区(这非常灵活,但要注意嵌入式系统上的计算器溢出:))。