C 指向函数内动态分配的缓冲区的静态指针

C 指向函数内动态分配的缓冲区的静态指针,c,numpy,malloc,C,Numpy,Malloc,我在C中有一个函数,它动态分配一个缓冲区,该缓冲区被传递给另一个函数来存储其返回值。类似于以下虚拟示例: void other_function(float in, float *out, int out_len) { /* Fills 'out' with 'out_len' values calculated from 'in' */ } void function(float *data, int data_len, float *out) { float *buf;

我在C中有一个函数,它动态分配一个缓冲区,该缓冲区被传递给另一个函数来存储其返回值。类似于以下虚拟示例:

void other_function(float in, float *out, int out_len) {
    /* Fills 'out' with 'out_len' values calculated from 'in' */
}

void function(float *data, int data_len, float *out) {
    float *buf;
    int buf_len = 2 * data_len, i;
    buf = malloc(sizeof(float) * buf_len);

    for (i = 0; i < data_len; i++, data++, out++) {
        other_function(*data, buf, buf_len);
        /* Do some other stuff with the contents of buf and write to *out */
    }
    free buf;
}

这意味着我从不直接释放分配的内存:它在后续调用中被重用,然后在那里逗留,直到我的程序退出。这似乎不是正确的做法,但也不是太糟糕,因为分配的内存量总是很小。我担心过度了吗?有更好的方法吗?

这是一种很好的方法,许多库可能在内部使用类似的方法。当程序退出时,内存将自动释放


您可能希望将
buf_len
四舍五入到某个块大小的倍数,这样您就不会每次
data_len
发生一点变化时都
realloc()
。但是,如果
数据长度几乎总是相同的,这是不必要的。

这种方法是合法的(但见下文),尽管像valgrind这样的工具会错误地将其标记为“泄漏”。(这不是泄漏,因为泄漏是内存使用量的无限增加。)与函数正在执行的其他操作相比,您可能希望准确地测试
malloc
free
上损失的时间

如果你可以使用C99或GCC,如果你的缓冲区不是太大,你也应该考虑可变长度数组,它与静态缓冲区一样快(或者比静态缓冲区快),并且不会产生碎片。如果您使用的是另一个编译器,则可以查看非标准(但)alloca扩展

您需要知道,使用静态缓冲区会使您的功能:

  • 线程不安全-如果同时从多个线程调用它,它将破坏另一个实例的数据。如果从numpy调用Python,这可能不是问题,因为GIL将有效地序列化线程

  • 不可重入-如果
    other_function
    调用某些Python代码,最终调用
    function
    -无论出于何种原因-在
    function
    完成之前,您的函数将再次销毁自己的数据


  • 如果您不需要真正的并行执行和可重入性,那么使用
    静态
    变量就可以了,很多C代码都是这样使用的。

    您对动态缓冲区的大小有什么保证吗?C中没有raii,可能您使用的编译器有gcc中的raii扩展:@JustinMeiners是的,它的控制非常严格。最多是65536个项目,但这很少见,通常是16或32个项目。我会使用
    我使用的是MSVC,我认为它是严格的C89,所以我认为没有VLA…线程安全性方面的优点。。。如果将其与
    多处理
    并行化。每个进程都会获得自己的静态变量副本吗?@Jaime Yes-单独的进程不会共享全局变量。
    void function(float *data, int data_len, float *out) {
        static float *buf = NULL;
        static int buf_len = 0;
        int i;
        if (buf_len != 2 * data_len) {
            buf_len = 2 * data_len;
            buf = realloc(buf, sizeof(float) * buf_len); /* same as malloc if buf == NULL */
        }
        for (i = 0; i < data_len; i++, data++, out++) {
            other_function(*data, buf, buf_len);
            /* Do some other stuff with the contents of buf and write to *out */
        }
    }